[leetcode]Best Time to Buy and Sell Stock 系列

  1. Best Time to Buy and Sell Stock
    reqest:只允许购买一次股票,即只能买入卖出一次

构建类似马尔科夫链的转态转移函数:
每个交易日可以又两种选择 buy 和sell
而buy和sell之间存在着先后关系,buy为第一次买入得到的最大利润,一定是负值,sell为第一次卖出得到的最大利润。

buy(i)=Math.max(buy(i-1),-prices[i]);
//实质是保存目前为止的最小交易值
sell(i)=Math.max(sell(i-1),buy(i-1)+prices[i]);
//在不断更新最小交易值的同时,不断判断目前交易天卖出是否是最大值。
必须先更新sell值,再更新buy,目的是为了利用上次迭代的buy去更新sell值
class Solution {
    public int maxProfit(int[] prices) {
        int buy=Integer.MIN_VALUE;
        int sell=0;
        int n=prices.length;
        for(int i=0;i<n;i++){
            sell=Math.max(sell,buy+prices[i]);
            buy=Math.max(buy,-prices[i]);
            
        }
        return sell;
        
    }
}
  1. Best Time to Buy and Sell Stock III
    request:可以最多两次次买入卖出

利用上面的思路,找状态转移方程,可以写出

sell2=Math.max(sell2,buy2+prices[i]);
//第二次买出的最大利润
buy2=Math.max(buy2,sell1-prices[i]);
//第二次买入的最大利润
sell1=Math.max(sell1,buy1+prices[i]);
//利用目前最大的买入利润得到第一次卖出的最大利润
buy1=Math.max(buy1,-prices[i]);
//保存第一次买入的最大利润,也就是交易额最小
所有变量是按照转态转移方程去不断更新优化,获得最佳值,
  1. Best Time to Buy and Sell Stock II
    requeat:可以多次买入买出,但每次买入必须在上一次卖出

    如果利用上述思路,继续使用状态转移方程,那么因为交易次数的不确定,最后得到的无数的状态转移方程,不可能实现,那么就要把状态转移方程合并成符合题目要求的样子
    可以看到在Best Time to Buy and Sell Stock,单次交易的解决方法,那么无数次交易可以看成是无数次单次交易,先找到在某个时刻点买入的股票能连续获利的的最大值,一旦哪天卖出是相较上一天是亏本,则得到了一次买卖的收入,然后再次重复
    其中的关键就是连续获利,也就是判断当天交易额是否比上一天高,高说明可以持续获利,低则说明买入的股票在上一天得到顶峰,上一天可以卖出,然后在寻找下一个连续获利的序列
    与一次买卖最大的区别在于,每次卖出获利不是全局最优值,但是无数个局部最优值的叠加,贪婪算法。

class Solution {
    public int maxProfit(int[] prices) {
        int min=Integer.MAX_VALUE;
        int max=0;
        int n = prices.length;
        for(int i=1;i<n;i++){
           if(prices[i]>prices[i-1])
               max+=prices[i]-prices[i-1];
        }
        return max;
    }
}

第二种方法,就是利用状态转移方程,对每次交易日的两种选择判断执行,这里的buy包含两种意思,之前卖了,当前天买入,或是之前买入了,然后一直保持在手里

class Solution {
    public int maxProfit(int[] prices) {
        int min=Integer.MAX_VALUE;
        int max=0;
        int n = prices.length;
        int[] buy=new int[n+1];
        buy[0]=Integer.MIN_VALUE;
        int[] sell=new int[n+1];
        for(int i=1;i<=n;i++){
           sell[i]=Math.max(sell[i-1],buy[i-1]+prices[i-1]);
           buy[i]=Math.max(buy[i-1],sell[i-1]-prices[i-1]);
        }
        return sell[n];
    }
}
  1. Best Time to Buy and Sell Stock IV
    request:
    指定交易次数k,然后求最大利润。

同样的从一次买卖中寻找线索
二次买卖是在每个交易日更新二次交易值,那么K次买卖是不是能更新k次交易日,这个思路明显是正确的。

class Solution {
    public int maxProfit(int k, int[] prices) {
        int n = prices.length;
        
        if(k==0||n<2)
            return 0;
        if (n/2 < k){
            return quickSolve(prices);
//因为当k次交易大于交易日的一般,也就是每天交易都打不到k次交易,则就可以按照无数次交易贪婪得到无数局部最优解的叠加
        }
        int[] hold = new int[k+1];
        for(int i=0;i<=k;i++){
            hold[i]=Integer.MIN_VALUE;
        }

        int[] unhold = new int[k+1];
        hold[1]=Integer.MIN_VALUE;
        for(int i=0;i<n;i++){
            for(int j=1;j<=k;j++){
                unhold[j]=Math.max(unhold[j],hold[j]+prices[i]);
                hold[j]=Math.max(hold[j],unhold[j-1]-prices[i]);
                
               //在每个交易日对k个买卖的值执行更新
                
            }
        }
        return unhold[k];
    }
    int quickSolve(int[] prices) {
        int len = prices.length, profit = 0;
        for (int i = 1; i < len; i++)
            // as long as there is a price gap, we gain a profit.
            if (prices[i] > prices[i - 1]) profit += prices[i] - prices[i - 1];
        return profit;
    }

}
  1. Best Time to Buy and Sell Stock with Cooldown
    request:可以多次交易,但是在卖出之后又一天的冷冻期不能买入
    同样利用状态转移方程,
    public int maxProfit(int[] prices) {
        /*
            重点在于表述状态转移方程,也就是从递归的角度描述,然后反向执行
            首先股票包含的状态为sell buy cool
            从递归的角度来看:
                股票在第i天能够执行的操作有 buy sell ,并且在卖和买之间有一天的cool,但是在买和卖之间同样存在隐藏的cool_hidden;
                判断第i天四种操作获取的最大利润
                buy[i]:cool[i-1]-price[i];
                cool_hidden[i]:cool_hidden[i-1];buy[i-1];
                sell[i]:cool_hidden[i-1]+price[i];buy[i-1]+price[i];
                cool[i]:sell[i-1];cool[i-1];
                这个状态太长,开始降维合并:
                首先,cool_hidden 可以合并到buy:hold操作就包含了buy和cool_hidden;
                cool也可以列合并到sell:unhold操作包含sell和cool

                hold[i]=max(hold[i-1],unhold[i-2]-price[i]);
                unhold[i]=max(unhold[i-1],hold[i-1]+price[i]);
        */
        int n = prices.length;
        if(n<2)
            return 0;
        int[] hold=new int[n];
        int[] unhold=new int[n];
        hold[0]=-prices[0];
        unhold[0]=0;
        hold[1]=Math.max(hold[0],unhold[0]-prices[1]);
        unhold[1]=Math.max(unhold[0],hold[0]+prices[1]);
        for(int i=2;i<n;i++){
            hold[i]=Math.max(hold[i-1],unhold[i-2]-prices[i]);
            unhold[i]=Math.max(unhold[i-1],hold[i-1]+prices[i]);
        }
        return Math.max(hold[n-1],unhold[n-1]);
                     
    }                     
}
6. Best Time to Buy and Sell Stock with Transaction Fee
request:每笔交易需要手续费,但不限交易次数

class Solution {
public int maxProfit(int[] prices, int fee) {
int n = prices.length;
int[] hold = new int[n];
int[] unhold=new int[n];
unhold[0]=0;
hold[0]=-prices[0];
for(int i=1;i<n;i++){
unhold[i]=Math.max(unhold[i-1],hold[i-1]+prices[i]-fee);
hold[i]=Math.max(hold[i-1],unhold[i-1]-prices[i]);
}
return unhold[n-1];
}
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容