Alpha-beta in Connect Four - artificial-intelligence

My minimax algorithm is returning very bad move choice after I apply alpha-beta pruning to the game of Connect Four.
def get_next_move(board, player, depth, alpha, beta) :
score = get_score(board, depth)
if score is not None :
return score, board
if depth == 0 :
return 0, board
if player is AI :
best = LOSS
best_move = None
possible_moves = get_possible_moves(board, player)
for move in possible_moves :
move_score = get_next_move(move, PLAYER, depth-1, alpha, beta)[0]
if move_score >= best :
best = move_score
best_move = move
alpha = max(alpha, best)
if alpha >= beta :
break
return best, best_move
else :
best = WIN
best_move = None
possible_moves = get_possible_moves(board, player)
for move in possible_moves :
move_score = get_next_move(move, AI, depth-1, alpha, beta)[0]
if move_score <= best :
best = move_score
best_move = move
beta = min(best, beta)
if beta <= alpha :
break
return best, best_move
Everything works fine until I try to implement alpha-beta.

Related

Minimax algorithm AI not picking the correct choice

I have tried to impliment the minimax algorithm with alpha/beta pruning for a TicTacToe game I'm making in the Godot Engine, however, it doesn't seem to work as expected. The AI seems to always pick the next available spot on the board from left to right. Can anyone let me know where I might have gone wrong?
Here's my code:
func winner_score() -> int:
# 0 is X, 1 is Y
if board.won(0)[0]: return -10
elif board.won(1)[0]: return 10
else: return 0
func minimax(_board, _depth: int, alpha, beta, maximizingPlayer: bool):
var result = winner_score()
if _depth == 0 or result != 0:
return result
if maximizingPlayer:
var maxEval: int = -100
for row in range(board.size):
for col in range(board.size):
var square = _board[row][col]
if square.type == null:
square.type = HUMAN
var eval: int = minimax(_board, _depth - 1, alpha, beta, false)
square.type = null
maxEval = max(maxEval, eval)
alpha = max(alpha, eval)
if beta <= alpha: break
return maxEval
else:
var minEval = 100
for row in range(board.size):
for col in range(board.size):
var square = _board[row][col]
if square.type == null:
square.type = AI
var eval: int = minimax(_board, _depth - 1, alpha, beta, true)
square.type = null
minEval = min(minEval, eval)
beta = min(beta, eval)
if beta <= alpha: break
return minEval

FT of a nonlinear term using FFTW3 and q = 0

I am trying to apply an integration algorithm for PDEs called Exponential Time Differencing using C language and the library FFTW3. Without going too much into details, I need to calculate the FT of a nonlinear term which is the derivative of a function squared:
The way I do it is the following:
1) Define lattice size
int Nx = 500;
double dx = 0.2;
2) Calculate wavevectors
for ( i = 0; i < Nx/2+1; i++ ) {
qx[i] = 2.0*i*pi/(Nx*dx);
}
3) Execute FFTW3 plan to obtain FT of h from initial conditions (IC not shown in the code)
plan_forward = fftw_plan_dft_r2c_1d (Nx,dh,dhft,FFTW_ESTIMATE); //dh -> dhft
fftw_execute (plan_forward);
4) Calculate the FT of derivative of h
for ( i = 0; i < Nx/2+1; i++ ) {
// dxhft[i][0] are the real parts and dxhft[i][1] are the imaginary
dxhft[i][0] = -qx[i] * dhft[i][1]; // Re[FTdxh] = -q Im[FTh]
dxhft[i][1] = qx[i] * dhft[i][0]; // Im[FTdxh] = q Re[FTh]
}
5) Set the Nyquist element to 0 (as explained e.g. here)
dxhft[Nx/2][0] = 0.0;
dxhft[Nx/2][1] = 0.0;
6) Transform the derivative in real space using inverse Fourier Transform
plan_backward = fftw_plan_dft_c2r_1d (Nx,dxhft,dxh,FFTW_ESTIMATE); //dxhft -> dxh
fftw_execute (plan_backward);
7) Normalise the derivative by Nx and calculate the nonlinear term
for ( i = 0; i < Nx; i++ ) {
dxh[i] = dxh[i] / (double) (Nx);
Nonl[i] = dxh[i]*dxh[i];
}
8) Transform the nonlinear term
fftw_execute_dft_r2c (plan_forward,Nonl,Nonlft); // Nonl -> Nonlft
Ok. Now, I have reasons to believe that the FT of the nonlinear term for q=0, that is the elements Nonlft[0][0] and Nonlft[0][1], is wrong. But I don't understand what I am missing in the code. Can anyone give me some insight on the problem?

Declaring a winner in a coin toss game

So, I'm running into an issue with the end of this program. It is supposed to award ten points for each correctly guessed coin flip, and at the end of the 100 tosses, a percentage of correct answers for each player as well as a total score, and finally it is to declare a winner. I seem to have the percentage correct, but the output for total score is jibberish, and I don't know how to get the program to use the results to declare a winner. Help?
#include "stdafx.h"
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int flip();
int main(void)
{
int player, side, toss, turn = 1, heads = 0, tails = 0;
int Play, wrong1, right1, wrong2, right2, r = (rand() % 2);
puts("Oh boy. My favorite game. Flip the coin. How super exciting. I apparently am little more than a childs plaything... \nEven though I am a program and thus do not have thumbs, hands, feet, skin or even a body, I will (reluctanly) play your silly little game, and 'flip a coin' 100 times.\nI hope you know, there are a lot better things I could be doing right now...\nReal quick, here's a list of things I could be doing right now.\n--Advance scientific research on globular clusters in the Milky Way Galaxy\n---Find the cure for cancer\n----Calculate the rate of deforestation in the Amazon\n-----Create the next generation of low emmission motor vehicles to lower the amount of CO2 in the atmosphere.\nBut, no. Let's play 'Flip the coin'. I couldn't possibly be more ecstatic, than if I woke this morning to see that I was on fire. While stapled to a wall. In New Jersey. With Kim Kardashian holding the fire extinguisher that is actually a can of hairspray... Yeah.\n");
puts("Are you player 1 or player 2?\n");//question to prompt user response
scanf_s("%d", &player);//how many players input
puts("\nSo, let's flip a coin, because apparently this game is the 'bees-nees' of the tech world... Enter 1 for heads, or 0 for tails.");
srand((unsigned)time(NULL));// seed random function with current time
for (toss = 1; toss <= 100; toss++)
{ //number of runs/tosses
if ( player=1)
if (turn == 1) // start of 2 player gaming
printf("\nPlayer 1, flip the coin. Player 2, take a guess.\n");// player 1 flip
else
printf("\nPlayer 2, it's your turn to flip the coin, Player 1 guess heads or tails.\n"); // player 2 flip
if (turn == 1)
Play = 1, turn = 0;
else
Play = 2, turn = 1;
printf("\nPlayer 1 toss the coin and guess the side\n");
int flipped;
scanf_s("\n %d", &side);// coin guess function
printf("\nThe coin came up %d\n", flip());
if (side == flip() && Play == 1)
right1++;
else
wrong1++;
if (side == flip() && Play == 2)
right2--;
else
wrong2++;
if (flip() == 1)
heads++;
else
tails++;
}
printf("heads was flipped %d times\n", heads);
printf("tails was flipped %d times\n", tails);
printf("Player 1 score %d \n", (right1 * 10) - (wrong1 * 5));// not working quite right player 1 eqation 1 //functions on the next 4 lines for score and confidence
printf("Player 1 confidence %d %'\n", (right1 * 2));//percent confidence player 1 Equation 2
printf("Player 2 score %d \n", (right2 * 10) - (wrong2 * 5));// not working quite right player 2 eqation 1
printf("Player 2 confidence %d %'\n", (right1 * 2));//percent confidence player 2 Equation 2
return 0;
}
int flip()// Coin flip function
{
int i = rand() % 2;
if (i == 0)
return 0;
else
return 1;
}
I strongly suggest properly formatting nested if statements with brackets and indentation.
if ( player=1)
if (turn == 1) // start of 2 player gaming
printf("\nPlayer 1, flip the coin. Player 2, take a guess.\n");// player 1 flip
else
printf("\nPlayer 2, it's your turn to flip the coin, Player 1 guess heads or tails.\n"); // player 2 flip
is much more difficult to read than
if ( player=1) {
if (turn == 1) { // start of 2 player gaming
printf("\nPlayer 1, flip the coin. Player 2, take a guess.\n");// player 1 flip
} else {
printf("\nPlayer 2, it's your turn to flip the coin, Player 1 guess heads or tails.\n"); // player 2 flip
}
}
And yes, as mentioned in the comments
if ( player=1) {
should be
if (player == 1) {
And
if (turn == 1)
Play = 1, turn = 0;
else
Play = 2, turn = 1;
should be
if (turn == 1) {
Play = 1;
turn = 0;
} else {
Play = 2;
turn = 1;
}
And you are also using right1, wrong1, right2, and wrong2 without initializing them.
And finally, in printf(), %' should be %% if you are trying to print a percent sign.

Find buy/sell prices in array of stock values to maximize positive difference

Got this question in an interview today, and its optimized solution stopped me cold (which blows, because I really wanted to work for this company...)
Given a single array of real values, each of which represents the stock value of a company after an arbitrary period of time, find the best buy price and its corresponding best sell price (buy low, sell high).
To illustrate with an example, let's take the stock ticker of Company Z:
55.39 109.23 48.29 81.59 105.53 94.45 12.24
Important to note is the fact that the array is "sorted" temporally - i.e. as time passes, values are appended to the right end of the array. Thus, our buy value will be (has to be) to the left of our sell value.
(in the above example, the ideal solution is to buy at 48.29 and sell at 105.53)
I came up with the naive solution easily enough with O(n2) complexity (implemented in java):
// returns a 2-element array: first element is the index in the argument array
// of the best buying price, and the second element is the index of the best
// selling price which, collectively, maximize the trading return
//
// if there is no favorable trading (e.g. prices monotonically fall), null is returned
public int[] maximizeReturn(ArrayList<Double> prices) {
int [] retval = new int[2];
int BUY = 0, SELL = 1;
retval[BUY] = retval[SELL] = -1; // indices of buy and sell prices, respectively
for (int i = 0; i < prices.size(); i++) {
for (int j = i + 1; j < prices.size(); j++) {
double difference = prices.get(j).doubleValue() -
prices.get(i).doubleValue();
if (difference > 0.0) {
if (retval[BUY] < 0 || difference > prices.get(retval[SELL]).doubleValue() -
prices.get(retval[BUY]).doubleValue()) {
retval[BUY] = i;
retval[SELL] = j;
}
}
}
}
return (retval[BUY] > 0 ? retval : null);
}
Here's where I screwed up: there's a linear time O(n) solution, and I completely bombed in trying to figure it out (yeah, I know, FAIL). Does anyone know how to implement the linear time solution? (any language you're comfortable with) Thanks!
Edit
I suppose, for anyone interested, I just received word today that I didn't get the job for which I interviewed where they asked me this question. :(
In C#:
static void Main(string[] args)
{
double[] values = new double[7]{55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24};
double max = double.MinValue, maxDiff = double.MinValue, diff = 0;
for (int i = 1; i < values.Length; i++)
{
if (values[i] > values[i - 1])
{
//trending upward, append to existing differential
diff += values[i] - values[i - 1];
}
else
{
//trending downward, reset the diff
diff = 0;
}
if (diff > maxDiff)
{
maxDiff = diff;
max = values[i];
}
}
Console.WriteLine("Buy at {0}; Sell at {1}", max - maxDiff, max);
}
EDIT: New algo based on #Joe's failing test case -- Nice Catch BTW! It's also the same answer as #Doug T's now...
static void Main(string[] args)
{
double[] values = new double[8] { 55.39, 109.23, 48.29, 81.59, 81.58, 105.53, 94.45, 12.24 };
double max = double.MinValue, maxDiff = double.MinValue, diff = 0;
double bottom = values[0];
for (int i = 1; i < values.Length; i++)
{
diff += values[i] - values[i - 1];
if (diff > maxDiff)
{
maxDiff = diff;
max = values[i];
}
if (values[i] < bottom)
{
bottom = values[i];
diff = 0;
}
}
Console.WriteLine("Buy at {0}; Sell at {1}", max - maxDiff, max);
}
Here's an attempt (C++). Basically everytime I track a new top, I try to see if thats the best profit thusfar. I know that the "bottom" must have been discovered earlier. At that point I remember the top, bottom, and the current max profit. If a new bottom is discovered later, its AFTER the current top, so we must reset top and see if a slightly lower "top" can yield better profit.
#include <iostream>
int main()
{
double REALLY_BIG_NO = 1e99;
double bottom = REALLY_BIG_NO; // arbirtrary large number
double currBestBuy = 0.0;
double top = 0.0;
double currBestSell = 0.0;
double profit = 0.0;
// array of prices
double prices[] = {10.50, 55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24, 152.0, 2, 170.0};
int numPrices = 10;// number of prices
for (int i = 0; i < numPrices; ++i)
{
if (prices[i] < bottom)
{
bottom = prices[i];
// reset the search on a new bottom
top = 0.0;
}
else if (prices[i] > top)
{
top = prices[i];
// calculate profit
double potentialProfit = (top - bottom);
if (potentialProfit > profit &&
bottom != REALLY_BIG_NO)
{
profit = potentialProfit;
currBestSell = top;
currBestBuy = bottom;
}
}
}
std::cout << "Best Buy: " << currBestBuy << "Best Sell: " << currBestSell << std::endl;
}
So far I've played around with a bunch of different input sets, and so far I haven't had any problems... (let me know if you test this and see anything wrong)
I highly recommend using Austin Salonen's updated answer to this question and adapting it to your language.
The idea is simple. Keep two pointers, lo and hi.
Do a Foor loop
if price is higher than hi, update hi = price, continue
if the price is lower than hi. Then lo and hi is one of possible candidates. Calculate the profit, store it if it's bigger than previous profits and reset lo, hi to price
def getBestProfit(prices):
lo = hi = profit = 0
for price in prices:
if lo == 0 and hi == 0:
lo = hi = price
if price > hi:
hi = price
if price < low:
tmpProfit = hi - lo
if tmpProfit > profit:
profit = tmpProfit
lo = hi = price
return profit
That's it
void getBestTime (int stocks[], int sz, int &buy, int &sell){
int min = 0;
int maxDiff = 0;
buy = sell = 0;
for (int i = 0; i < sz; i++)
{
if (stocks[i] < stocks[min])
{
min = i;
}
int diff = stocks[i] - stocks[min];
if (diff > maxDiff)
{
buy = min;
sell = i;
maxDiff = diff;
}
}}
Just in case you prefer this answer. I found it in another web, but still.
source:http://leetcode.com/2010/11/best-time-to-buy-and-sell-stock.html
public void profit(float stock[], int arlen ){
float buy = stock[0];
float sell = stock[arlen-1];
int bi = 0;
int si = arlen - 1;
for( int i = 0; i < arlen && bi < si ; i++){
if( stock[i] < buy && i < si){
buy = stock[i];
bi = i;
}
if(stock[arlen - i - 1] > sell && (arlen - i -1) > bi){
sell = stock[arlen - i - 1];
si = arlen - i - 1;
}
}
System.out.println(buy+" "+sell);
}
I really have to point out as an interview question expecting you to solve it as O(n) is borderline absurd. Interview questions are meant to prove you can solve a problem, which you were able to solve it. The fact you solved it in O(N^2) vs O(N) should be irrelevant. If a company would pass over hiring you for not solving this in O(N) that's probably not a company you would have wanted to work at anyway.
I'd like to describe how I approached this problem to make it easier to understand my code:
(1) For each day, if I had to sell my stock on that day, what would be the minimum amount I could have paid to buy it? Essentially, I'm keeping track of minimum price before that day
(2) For each day, if I were to sell on that day, how much am I earning? (Stock price on that day - minimum price)
This shows that I have to keep track of two things: (1) minimum stock price so far (2) best earning so far.
The problem becomes choosing which day to sell. I will sell on the day that will give me the best earning. Here is my Java code:
public static void findBestDeal(double [] stocks) {
double minsofar = stocks[0];
double bestsofar = 0.0;
for(int i=1; i< stocks.length; i++) {
// What is the cheapest price to buy it if I'm going to sell it today
if(stocks[i-1] < minsofar) {
minsofar = stocks[i-1];
}
// How much do I earn if I sell it on ith day?
double current_deal = stocks[i] - minsofar;
// Is selling today better?
if(current_deal > bestsofar) {
bestsofar = current_deal;
}
}
System.out.println("Found the best deal: " + bestsofar + " (Bought at " + minsofar + " and sold at " + (minsofar+bestsofar) + ")");
}
Here is my O(n) implementation for this. I am using a change array to calculate the max profit and buy and sell dates.
Your comments on this are welcome.
#include<stdafx.h>
#include<stdio.h>
int main()
{
//int arr[10] = {15, 3, 5,9,10,1,6,4,7,2};
int arr[7] = {55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24};
int change[7];
int n=7;
for(int i=1;i<=n;i++)
{
change[i] = arr[i]- arr[i-1];
}
int i=0,index = 0;
int sum = 0;
int maxsum = 0;
int startpos = 0;
int endpos = 0;
while(index < n)
{
sum = sum + change[index];
if(maxsum < sum)
{
maxsum = sum;
startpos = i;
endpos = index;
}
else if (sum<0) // negative number ,set sum to zero
{
sum = 0;
i=index+1;
}
index++;
}
printf("max profit is%d %d %d", maxsum , startpos, endpos+1 );
}
In my effort to learn Go, and also to rake my brain on this one, here is my attempt.
func GetMaxProfit2(prices []float64) (float64, float64) {
var min, max, pmin, pmax int
for i, v := range prices {
if v - prices[min] > prices[max] - prices[min] {
pmax = max
max = i
}
// Reset the max when min is updated.
if v < prices[min] {
pmin = min
min = i
pmax = max
max = i
}
}
// If min is ahead of max, reset the values back
if min >= max {
min = pmin
max = pmax
}
return prices[min], prices[max]
}
Here is my attempt using Javascript. The script computes the answer in O(N):
//Main Stock Array
var stock = [15, 20, 0, 3, 30, 45, 67, 92, 1, 4, 99];
//Setup initial variable state
var ans = {}, tmp = {}; //These are just for namespacing / syntatic sugar
ans.minVal = stock[0];
ans.minInd = 0;
ans.maxDiff = stock[1] - stock[0];
ans.maxInd = 1;
tmp.minInd = ans.minInd;
tmp.minVal = ans.minVal;
//Basically we iterate throught the array. If we find a new low, we start tracking it. Otherwise we compare the current index against the previously found low
for(i = 1; i <= stock.length-1; i++) {
if(tmp.minVal > stock[i]) {
tmp.minVal = stock[i];
tmp.minInd = i;
} else {
ans.diff = stock[i] - stock[tmp.minInd];
if(ans.diff > ans.maxDiff) { //Looks like we found a new maxDifference. Lets log the indexes
ans.maxDiff = ans.diff;
ans.maxInd = i;
ans.minInd = tmp.minInd;
ans.minVal = tmp.minVal;
}
}
}
document.write('You should buy your stocks on day ' + ans.minInd + ' and sell on day ' + ans.maxInd);
This is a C solution that actually works:
void bestBuySell()
{
double prices[] = {10.50, 10.0, 3.0, 194.0, 55.39, 2.0, 109.23, 48.29, 81.59, 105.53, 94.45, 191.0, 200.0, 12.24};
int arrSize = 14;
double bestBuy = prices[0], bestSell = prices[1], bestPotentialBuy = prices[0];
double potentialProfit = prices[1] - prices[0];
for(int i = 1; i < (arrSize-1); i++)
{
if(prices[i] < bestBuy)
bestPotentialBuy = prices[i];
if((prices[i+1] - bestPotentialBuy) > potentialProfit)
{
bestBuy = bestPotentialBuy;
bestSell = prices[i+1];
potentialProfit = prices[i+1] - bestPotentialBuy;
}
}
printf( "bestBuy %f bestSell %f\n", bestBuy, bestSell );
}
1.We cant simply take the least amount among the values as " Best Buy" and the max amount as "Best Sell" because "Sell" has to happen after "Buy".
2.We must not treat the recorded minimum as the "Best Buy" because the subsequent days may have stock values whose difference with the recorded minimum may yield profit which could be less than the "recorded profit".
3.Best Buy and Best Sell is treated as a single variant,because it is the positive difference between these values that makes max profit.
4.Since any recorded minimum in the past is a potential candidate for buying,the max profit condition must always be checked against the recorded minimum and the current day's stock price.So we always have to keep track of recorded minimum,but just the presence of recorded minimum doesn't constitute "Best Buy" because of reason number 2.
Now have the below code which executes in O(n) times will make sense.
public class BestStockBuyAndSell {
public static void main(String[] args) {
double[] stockPrices = {55.39,109.23,48.29,81.59,105.53,94.45,12.24};
int [] bestBuySellIndex = maxProfit(stockPrices);
System.out.println("Best Buy At "+stockPrices[bestBuySellIndex[0]]);
System.out.println("Best Sell At "+stockPrices[bestBuySellIndex[1]]);
System.out.println("Max Profit = "+(stockPrices[bestBuySellIndex[1]]-stockPrices[bestBuySellIndex[0]]));
}
public static int[] maxProfit(double[] stockPrices)
{
int bestBuy=0;
int bestSell=0;
int[] bestCombination ={bestBuy,bestSell};
double recordedMinimum = stockPrices[bestBuy];
int recordedMinimuIndex = bestBuy;
double bestProfitSofar = stockPrices[bestSell] - stockPrices[bestBuy];
for(int i=1;i<stockPrices.length;i++)
{
if(stockPrices[i] - recordedMinimum > bestProfitSofar)
{
bestProfitSofar = stockPrices[i] - recordedMinimum;
bestSell = i;
bestBuy = recordedMinimuIndex;
}
if(stockPrices[i] < recordedMinimum)
{
recordedMinimuIndex = i;
recordedMinimum = stockPrices[i];
}
}
bestCombination[0] = bestBuy;
bestCombination[1] = bestSell;
return bestCombination;
}
}
I came up with following algorithm for this problem, seems to work for all inputs. Also, If the Stock value keeps droping, the program would output not to buy this stock:
public class GetMaxProfit
{
double minValue = -1, maxValue = -1;
double maxDiff = 0;
public void getProfit(double [] inputArray){
int i=0, j=1;
double newDiff = 0;
while(j<inputArray.length){
newDiff = inputArray[j]-inputArray[i];
if(newDiff > 0){
if(newDiff > this.maxDiff){
this.minValue = inputArray[i];
this.maxValue = inputArray[j];
this.maxDiff = newDiff;
}
}
else{
i = j;
}
j++;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
GetMaxProfit obj = new GetMaxProfit();
obj.getProfit(new double[]{55.39, 19.23, 14.29, 11.59, 10.53, 9.45, 1.24});
if(obj.minValue != -1 && obj.maxValue != -1){
System.out.println("Buy Value for the input: "+obj.minValue);
System.out.println("Sell Value for the input: "+obj.maxValue);
System.out.println("Best profit for the input: "+obj.maxDiff);
}
else
System.out.println("Do Not Buy This STOCK!!);
}
}
Is there any catch you could find in this? It's time complexity is O(N)
Here is my solution, same as #Doug T. except I am also keeping track of the day in an index. Please provide feedback.
int prices[] = {4,4,5,6,2,5,1,1};
//int prices[] = {100, 180, 260, 310, 40, 535, 695};
int currentBestSellPrice=0;
int currentBestBuyPrice=0;
int lowindex=0;
int highindex=0;
int low=prices[0];
int high=prices[0];
int profit=0;
int templowindex=0;
for(int i=0; i< prices.length;i++)
{
// buy low
if(prices[i] < low && i+1 < prices.length)
{
low = prices[i];
templowindex=i;
high=0;
}
// sell high
else if(prices[i] > high)
{
high = prices[i];
int potentialprofit = (high-low);
if(potentialprofit > profit)
{
profit = potentialprofit;
currentBestSellPrice = high;
currentBestBuyPrice = low;
highindex=i;
lowindex=templowindex;
}
}
}
System.out.println("Best Buy Price : "+ currentBestBuyPrice + " on day "+ lowindex);
System.out.println("Best Sell Price : "+ currentBestSellPrice+ " on day "+ highindex );
F# solution for those who interested in functional take on this. I wouldn't say though it's that much different.
let start, _, profit =
[55.39; 109.23; 48.29; 81.59; 81.58; 105.53; 94.45; 12.24 ]
|> Seq.fold (fun (start,newStart,profit) i ->
let start = defaultArg start i
let newStart = defaultArg newStart i
let newProfit = i - newStart
if profit < newProfit
then Some newStart, Some newStart,newProfit
else if start > i
then Some start, Some i, profit
else Some start,Some newStart,profit) (None,None, 0.0)
printf "Best buy: %f; Best sell: %f" start.Value (start.Value + profit)
Output:
Best buy: 48.290000; Best sell: 105.530000
Here is my solution in Ruby:
values = [55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24]
max_diff = 0
diff = 0
min = values[0]
max = 0
values.each_with_index do |value, index = 1|
# get an array of the previous values before the current one
lag_values = values[0..index]
# get the minimum of those previous values
min_lag_value = lag_values.min
# difference between current value and minimum of previous ones
diff = values[index].to_i - min_lag_value.to_i
# if current difference is > previous max difference, then set new values for min, max_diff, and max
if diff > max_diff
max_diff = diff
min = min_lag_value
max = values[index]
end
end
min # => 48.29
max # => 105.3
max_diff # => 57
Cheers
I got 100% for the same, here you go.
public int solution(int[] A) {
if (A == null || A.length<=1){
return 0;
}
int minValue = Math.min(A[0], A[1]);
int profit = A[1] - A[0];
for (int i = 2; i < A.length; i++) {
minValue = Math.min(minValue, A[i]);
profit = Math.max(A[i] - minValue,profit);
}
return profit > 0 ? profit : 0;
}
The way I thought about this was, for every index i what would be the ideal index be for selling this stock? This is of course, the index of the maximum value after i. This reduces our problem to finding the maximum element after index i for each i in [1 ... n] If we could do that in O(n) time, then we could find the best choice amongst those and report it.
A way to do this is to start traversing from the end of the array, maintaining two variables, one to save the largest element we have encountered so far max_till_now, and one to save the maximum profit we could get till now, profit. This is just so that we can do this in one pass. We could also use extra space and for each element i, store the index of the largest element in the range [i + 1 ... n] for it and then find the maximum profit.
Here's my python code:
def buyLowSellHigh(L):
length = len(L)
profit = 0
max_till_now = L[length - 1]
for i in xrange(length - 2, -1, -1):
if L[i] > max_till_now: max_till_now = L[i]
else:
if max_till_now - L[i] > profit: profit = max_till_now - L[i]
return profit
Another Ruby solution:
# Here's some examples. Please feel free to give your new test.
values = [55.39, 109.23, 48.29, 81.59, 105.53, 94.45, 12.24]
# values = [5, 6, 4, 7, 9, 8, 8]
# values = [5, 10, 4, 6, 7]
# values = [5, 10, 4, 6, 12]
# values = [1, 2, 3, 4, 5]
# Initialize parameters.
min = values[0]
best_buy_time = values[0]
best_sell_time = values[0]
max_profit = 0
# This solution is based on comparing previous k elements and k+1 one.
# The runtime is O(n) and it only use O(1) auxiliary storage.
values.each_with_index do |value, index = 1|
# Check value in this turn.
puts value
# Check current value is bigger than min or not.
# If not, we find the new min.
if value <= min
min = value
# If current value is bigger than min and
# (value - min) is bigger than previous max_profit,
# set new best_buy_time, best_sell_time & max_profit.
else
if value - min >= max_profit
best_buy_time = min
best_sell_time = value
max_profit = value - min
end
end
end
# Let's see about the result.
puts "\nbest_buy_time: ", best_buy_time, "\nbest_sell_time: ", best_sell_time, "\nmax_profit: ", max_profit
what about this?
min = 100000000
max = 0
for elem in inp:
if elem < min:
min = elem
tempMax = elem-min
if tempMax > max:
max = tempMax
print(max)
Solution in javascript
var stockArr = [13931, 9889, 987, 4, 89, 100];
function getBestTime(sortedArr) {
var min = 0;
var buyIndx = 0;
var saleIndx = 0;
var maxDiff = 0;
for (var i = 0; i < stockArr.length; i++) {
if (stockArr[i] < stockArr[min]) {
min = i;
}
var diff = stockArr[i] - stockArr[min];
if (diff > maxDiff) {
buy = min;
sale = i;
maxDiff = diff;
}
}
return {
buy:buy+1,
sale:sale+1,
diff:maxDiff
}
}
console.log(getBestTime(stockArr));
Heres a javascript solution..
function getMax(arr){
//we need more than at least 3 ints to be able to do this
if(arr.length <= 1) return arr;
// get the minimum price we can sell at to make a profit
var min = arr[0];
//get the first potential maximum profit
var max = arr[1] - arr[0];
//while looping through we must get a potential value,
//we can then compare that using the math.max using the maximum
//and the potential prices that we have seen. Once the loop runs the ouput here should be 6!
for(var i = 1; i < arr.length; ++i){
var current = arr[i];
var potential = current - min;
max = Math.max(max, potential);
min = Math.min(min, current);
}
return max;
}
console.log(getMax([10, 7, 5, 8, 11, 9]));
Runtime on this is O(n)
Solution in scala :
Example : [ 7, 2, 5, 6, 1, 3, 6, 4 ]
Keep a pointer to the last minimum stock price(lastStockPrice) and compare it to the current stock price. When you reach a point where the current stock price < last minimun stock price, you update the lastStockPrice.
While looping through the array, keep a track of the max difference (profit) between the currentPrice and the lastStockPrice as the profit can change when you update the lastStockPrice.
The below scala code works in O(n) time and takes a constant amount of space.
object Solution {
def maxProfit(prices: Array[Int]): Int = {
var lastStockPrice = Int.MaxValue
var maxProfit = 0
for(currentPrice <- prices){
if(currentPrice < lastStockPrice){
lastStockPrice = currentPrice;
}else if(currentPrice - lastStockPrice > maxProfit){
maxProfit = currentPrice - lastStockPrice;
}
}
maxProfit
}
}
The logic to solve this problem is same as "max subarray problem" using Kadane's Algorithm. Since no body has mentioned this so far, I thought it's a good thing for everybody to know.
All the straight forward solution should work, but if the interviewer twists the question slightly by giving the difference array of prices, Ex: for {1, 7, 4, 11}, if he gives {0, 6, -3, 7}, you might end up being confused.
Here, the logic is to calculate the difference (maxCur += prices[i] - prices[i-1]) of the original array, and find a contiguous subarray giving maximum profit. If the difference falls below 0, reset it to zero.
class Solution:
def maxProfit(self, prices: List[int]) -> int:
_currmax = 0
_globalMax = 0
for i in range(1,len(prices)):
_currmax = max(_currmax+(prices[i]-prices[i-1]),0)
_globalMax = max(_globalMax,_currmax)
return _globalMax

Union of intervals

I've got a class representing an interval. This class has two properties "start" and "end" of a comparable type. Now I'm searching for an efficient algorithm to take the union of a set of such intervals.
Thanks in advance.
Sort them by one of the terms (start, for example), then check for overlaps with its (right-hand) neighbor as you move through the list.
class tp:
def __repr__(self):
return "(%d,%d)" % (self.start, self.end)
def __init__(self, start, end):
self.start = start
self.end = end
s = [tp(5, 10), tp(7, 8), tp(0, 5)]
s.sort(key=lambda self: self.start)
y = [s[0]]
for x in s[1:]:
if y[-1].end < x.start:
y.append(x)
elif y[-1].end == x.start:
y[-1].end = x.end
Use the sweep line algorithm. Basically, you sort all the values in a list (while keeping whether it's beginning or end of the interval along with each item). This operation is O(n log n). Then you loop in a single pass along the sorted items and compute the intervals O(n).
O(n log n) + O(n) = O(n log n)
It turns out this problem has been solved, many times over -- at varying levels of fancy, going under nomenclature(s): http://en.wikipedia.org/wiki/Interval_tree , http://en.wikipedia.org/wiki/Segment_tree , and also 'RangeTree'
(as OP's question involves large counts of intervals these datastructures matter )
in terms of my own choice of python library selection:
From testing, I'm finding that what most nails it in terms of being full featured and python current ( non bit-rotted ) : the 'Interval' and 'Union' classes from SymPy, see : http://sympystats.wordpress.com/2012/03/30/simplifying-sets/
Another good looking choice, a higher performance but less feature rich option (eg. didn't work on floating point range removal) : https://pypi.python.org/pypi/Banyan
Finally: search around on SO itself, under any of IntervalTree, SegmentTree, RangeTree, and you'll find answers/hooks further galore
Sort all the points. Then go through the list incrementing a counter for "start" points, and decrementing it for "end" points. If the counter reaches 0, then it really is an endpoint of one of the intervals in the union.
The counter will never go negative, and will reach 0 at the end of the list.
The algorithm by geocar fails when:
s=[tp(0,1),tp(0,3)]
I'm not very sure but I think this is the correct way:
class tp():
def __repr__(self):
return '(%.2f,%.2f)' % (self.start, self.end)
def __init__(self,start,end):
self.start=start
self.end=end
s=[tp(0,1),tp(0,3),tp(4,5)]
s.sort(key=lambda self: self.start)
print s
y=[ s[0] ]
for x in s[1:]:
if y[-1].end < x.start:
y.append(x)
elif y[-1].end == x.start:
y[-1].end = x.end
if x.end > y[-1].end:
y[-1].end = x.end
print y
I also implemented it for subtraction:
#subtraction
z=tp(1.5,5) #interval to be subtracted
s=[tp(0,1),tp(0,3), tp(3,4),tp(4,6)]
s.sort(key=lambda self: self.start)
print s
for x in s[:]:
if z.end < x.start:
break
elif z.start < x.start and z.end > x.start and z.end < x.end:
x.start=z.end
elif z.start < x.start and z.end > x.end:
s.remove(x)
elif z.start > x.start and z.end < x.end:
s.append(tp(x.start,z.start))
s.append(tp(z.end,x.end))
s.remove(x)
elif z.start > x.start and z.start < x.end and z.end > x.end:
x.end=z.start
elif z.start > x.end:
continue
print s
To find the total of the union of intervals in c++
#include <iostream>
#include <algorithm>
struct interval
{
int m_start;
int m_end;
};
int main()
{
interval arr[] = { { 9, 10 }, { 5, 9 }, { 3, 4 }, { 8, 11 } };
std::sort(
arr,
arr + sizeof(arr) / sizeof(interval),
[](const auto& i, const auto& j) { return i.m_start < j.m_start; });
int total = 0;
auto current = arr[0];
for (const auto& i : arr)
{
if (i.m_start >= current.m_end)
{
total += current.m_end - current.m_start;
current = i;
}
else if (i.m_end > current.m_end)
{
current.m_end = i.m_end;
}
}
total += current.m_end - current.m_start;
std::cout << total << std::endl;
}

Resources