股票买卖问题

来源:互联网 发布:大型数据库有哪些 编辑:程序博客网 时间:2024/04/20 19:53

1. 题目描述

Say you have an array for which the ith element is the price of a given stock on day i.
If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

1. 题目解答

限制了只能买卖一次。于是要尽可能在最低点买入最高点抛出。这里的一个隐含的限制是抛出的时间必须在买入的时间之后。

  1. 如果prices[i] < minPrice,则更新minPrice = prices[i]。并且该天不应该卖出。
  2. 如果prices[i] >= minPrice,则该天可能是最好的卖出时间,计算prices[i] - minPrice,并与当前的单笔最大利润比较更新。
public class Solution {    public int maxProfit(int[] prices) {        if(prices == null || prices.length == 0)            return 0;        int minPrice = prices[0];        int retProfit = 0;        int len = prices.length;        for(int i = 1; i < len; i++) {            if(prices[i] < minPrice) {                minPrice = prices[i];            }else {                retProfit = Math.max(prices[i]-minPrice, retProfit);            }        }        return retProfit;    }}

2. 题目描述

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

2. 题目解答

并没有限制总的买卖次数,只限制了当天只能买或卖。所以可以采用greedy的方法,来获得所有可能的正利润。
只要prices[i] - prices[i-1]>0,我们就在第i-1天买入,第i天抛出。这样可以包括所有可能赚取利润的区间。
如果连续增长,3 4 5 ,相当与4没有买

public int maxProfit(int[] prices) {        if(prices == null || prices.length == 0)            return 0;        int minPrice = prices[0];        int retProfit = 0;        int len = prices.length;        for(int i = 1; i < len; i++) {            retProfit += ((prices[i] > prices[i-1]) ? (prices[i] - prices[i-1]) : 0);        }        return retProfit;    }

3. 题目描述

Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most two transactions.

Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

3. 题目解答

允许两次买卖,但同一时间只允许持有一支股票。也就意味着这两次买卖在时间跨度上不能有重叠(当然第一次的卖出时间和第二次的买入时间可以是同一天)。既然不能有重叠可以将整个序列以任意坐标i为分割点,分割成两部分:
prices[0:n-1] => prices[0:i] + prices[i:n-1]

  1. 计算A[0:i]的收益最大值:用minPrice记录i左边的最低价格,用maxLeftProfit记录左侧最大收益
  2. 计算A[i:n-1]的收益最大值:用maxPrices记录i右边的最高价格,用maxRightProfit记录右侧最大收益。
  3. 最后这两个收益之和便是以i为分割的最大收益。将序列从左向右扫一遍可以获取1,从右向左扫一遍可以获取2。相加后取最大值即为答案。
public class Solution {    public int maxProfit(int[] prices) {//      1. 计算A[0:i]的收益最大值:用minPrice记录i左边的最低价格,用maxLeftProfit记录左侧最大收益//      2. 计算A[i:n-1]的收益最大值:用maxPrices记录i右边的最高价格,用maxRightProfit记录右侧最大收益。//      3. 最后这两个收益之和便是以i为分割的最大收益。将序列从左向右扫一遍可以获取1,从右向左扫一遍可以获取2。相加后取最大值即为答案。        if(prices == null || prices.length == 0)            return 0;        int len = prices.length;        int[] leftProfits = new int[len];        int minPrice = prices[0];        int maxLeftProfit = 0;        //从左到右扫一遍        for(int i = 1; i < len; i++) {            if(prices[i] < minPrice) {                minPrice = prices[i];            }else {                maxLeftProfit = Math.max(maxLeftProfit, prices[i]-minPrice);            }            leftProfits[i] = maxLeftProfit;        }        //从右到左扫一遍        int retProfit = leftProfits[len-1];        int maxPrice = prices[len-1];        int maxRightProfit = 0;        for(int i = len-2; i >= 0; i--) {            if(prices[i] > maxPrice) {                maxPrice = prices[i];            }else {                maxRightProfit = Math.max(maxRightProfit, maxPrice-prices[i]);            }            retProfit = Math.max(retProfit, maxRightProfit+leftProfits[i]);        }        return retProfit;    }}

4. 题目描述

Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most k transactions.

Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

4. 题目解答

需要两个递推公式来分别更新两个变量local和global,我们其实可以求至少k次交易的最大利润。我们定义local[i][j]为在到达第i天时最多可进行j次交易并且最后一次交易在最后一天卖出的最大利润,此为局部最优。然后我们定义global[i][j]为在到达第i天时最多可进行j次交易的最大利润,此为全局最优。它们的递推式为:

local[i][j] = max(global[i - 1][j - 1] + max(diff, 0), local[i - 1][j] + diff),其中diff = prices[i] - prices[i-1]; global[i-1][j-1]表示第i-1天最多进行j-1次交易获得的最大利润,如果diff大于0,那么那么就加上今天获得利润,diff<0,那么最后一次就可以看做是当天买入并卖出。local[i-1][j]表示第i-1天最多进行j次交易获得的利润,加上diff就等于local[i][j]。 取两者最大值。

global[i][j] = max(local[i][j], global[i - 1][j]),也就是去当前局部最好的,和过往全局最好的中大的那个

public class Solution {    public int maxProfit(int k, int[] prices) {//       local[i][j] = max(global[i - 1][j - 1] + max(diff, 0), local[i - 1][j] + diff)//       global[i][j] = max(local[i][j], global[i - 1][j]),        if(prices == null || prices.length == 0)            return 0;        int len = prices.length;        if(k >= len/2)            return maxProfit2(prices);        int[] lp = new int[k+1];        int[] gp = new int[k+1];        for(int i = 1; i < len; i++) {            int diff = prices[i] - prices[i-1];            //所以从K到1开始遍历            for(int j = k; j > 0; j--) {                // gp[j-1]表示上一次的, lp[j] 表示上次的                lp[j] = Math.max(gp[j - 1] + Math.max(diff, 0), lp[j]+diff);                //gp[j] 表示上一次的                gp[j] = Math.max(gp[j], lp[j]);            }        }        return gp[k];    }    public int maxProfit2(int[] prices) {        //只要prices[i] - prices[i-1]>0,我们就在第i-1天买入,第i天抛出。        // 这样可以包括所有可能赚取利润的区间。        if(prices == null || prices.length == 0)            return 0;        int retProfit = 0;        int len = prices.length;        for(int i = 1; i < len; i++) {            retProfit += ((prices[i] > prices[i-1]) ? (prices[i] - prices[i-1]) : 0);        }        return retProfit;    }}

5. 题目描述

Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:


  • You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
  • After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)

prices = [1, 2, 3, 0, 2]
maxProfit = 3
transactions = [buy, sell, cooldown, buy, sell]

5. 题目解答

对于某一天,股票有三种状态: buy, sell, cooldown, sell与cooldown我们可以合并成一种状态
buy[i]表示在第i天之前最后一个操作是买,此时的最大收益。
sell[i]表示在第i天之前最后一个操作是卖,此时的最大收益。

  1. 对于当天最终未持股的状态,最终最大利润有两种可能,一是今天没动作跟昨天未持股状态一样,二是昨天持股了,今天卖了。所以我们只要取这两者之间最大值即可,表达式如下:
    sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i]);
  2. 对于当天最终持股的状态,最终最大利润有两种可能,一是今天没动作跟昨天持股状态一样,二是前天还没持股,今天买了股票,这里是因为cooldown的原因,所以今天买股要追溯到前天的状态。我们只要取这两者之间最大值即可,表达式如下:
    buy[i] = Math.max(buy[i - 1], sell[i - 2] - prices[i]);
  3. 最终我们要求的结果是
    sell[n - 1] 表示最后一天结束时手里没股票时的累积最大利润
public class Solution {    public int maxProfit(int[] prices) {        if(prices == null || prices.length == 0)            return 0;        int len = prices.length;        int[] sell = new int[len];        int[] buy = new int[len];        sell[0] = 0;        buy[0] = -prices[0];        for(int i = 1; i < prices.length; i++) {            sell[i] = Math.max(sell[i-1], buy[i-1]+prices[i]);            if(i >= 2) {                buy[i] = Math.max(buy[i-1], sell[i-2]-prices[i]);            }else {                buy[i] = Math.max(buy[i-1], -prices[i]);            }        }        return sell[len-1];    }}
0 0
原创粉丝点击