算法<Best Time to Buy and Sell Stock>

来源:互联网 发布:手机聚合软件 编辑:程序博客网 时间:2024/06/01 19:47

算法的题目是这样的:
有一个一维数组,数组的下标表示日期,下标对应的元素为该日股票的价格,请设计一个算法来求出股票买入和卖出的最大收益。

Example 1:

Input: [7, 1, 5, 3, 6, 4]Output: 5max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price)

Example 2:

Input: [7, 6, 4, 3, 1]Output: 0In this case, no transaction is done, i.e. max profit = 0.

这题可以使用Kadane’s Algorithm来在O(n)的时间内求解,首先来了解一下这个算法,以下文字来自维基百科:

*******************************************************

Kadane算法扫描一次整个数列的所有数值,在每一个扫描点计算以该点数值为结束点的子数列的最大和(正数和)。该子数列由两部分组成:以前一个位置为结束点的最大子数列、该位置的数值。因为该算法用到了“最佳子结构”(以每个位置为终点的最大子数列都是基于其前一位置的最大子数列计算得出),该算法可看成动态规划的一个例子。
算法可用如下Python代码实现:

def max_subarray(A):    max_ending_here = max_so_far = A[0]    for x in A[1:]:        max_ending_here = max(x, max_ending_here + x)        max_so_far = max(max_so_far, max_ending_here)    return max_so_far

该问题的一个变种是:如果数列中含有负数元素,允许返回长度为零的子数列。该问题可用如下代码解决:

def max_subarray(A):    max_ending_here = max_so_far = A[0]    for x in A[1:]:        max_ending_here = max(0, max_ending_here + x)        max_so_far = max(max_so_far, max_ending_here)    return max_so_far

*******************************************************

这就是一个DP问题,上面的解释十分详细,以下是Java实现:

public int maxSubArray(int[] nums) {        if(nums.length<1)            return 0;        int maxEndingHere =0,maxSofar =0;        for(int i=0; i<nums.length; i++){            maxEndingHere = Math.max(nums[i], maxEndingHere+nums[i]);            maxSofar= Math.max(maxSofar, maxEndingHere);        }        return maxSofar;    }

事实上如果我们的股票价格数组中的元素如下:

A1、A2、A3、A4、A5、A6

每相邻两天的股票之差组成的数组(实际意义就是头一天买了股票第二天就卖掉了):

d1,d2,d3,d4,d5d1=A2-A1;d2=A3-A2;d3=A4-A3;d4=A5-A4;d5=A6-A5;

假如我们在dn组成的数组中求得了和为最大的子串,那又代表了什么呢?

比如现在我们求得了dn数组的和为最大的子串是:

d2,d3,d4

之和为sum=d2+d3+d4=A3-A2+A4-A3+A5-A4=A5-A2.

这不就满足题目要求了嘛,第二天买入,第五天卖出,得到的收益是最大的。用算法来表述就是:

public int maxProfit(int[] prices) {        if(prices.length<2)            return 0;        int diff[] = new int[prices.length-1];        for(int i=1; i<prices.length; i++){            diff[i-1] = prices[i] - prices[i-1];        }        return maxSubArray(diff);    }    public int maxSubArray(int[] nums) {        if(nums.length<1)            return 0;        int maxEndingHere =0,maxSofar =0;        for(int i=0; i<nums.length; i++){            maxEndingHere = Math.max(nums[i], maxEndingHere+nums[i]);            maxSofar= Math.max(maxSofar, maxEndingHere);        }        return maxSofar;    }

得到这个代码之后其实我们可以简化为:

public int maxProfit(int[] prices) {        int maxCur = 0, maxSoFar = 0;        for(int i = 1; i < prices.length; i++) {            maxCur = Math.max(prices[i] - prices[i - 1], maxCur + prices[i] - prices[i - 1]);            maxSoFar = Math.max(maxCur, maxSoFar);        }        return maxSoFar;    }

至此貌似问题已经得到解决了,但是这个代码可能会返回负值,因为prices[i] - prices[i - 1]是有可能为负值的,而负值是不符合题意的,因此做以下修改便能解决问题:

 public int maxProfit(int[] prices) {        int maxCur = 0, maxSoFar = 0;        for(int i = 1; i < prices.length; i++) {            maxCur = Math.max(0, maxCur + prices[i] - prices[i - 1]);            maxSoFar = Math.max(maxCur, maxSoFar);        }        return maxSoFar;    }
原创粉丝点击