买卖股票的最佳时机 II -数学推导证明贪心思路 -leetcode122

48 篇文章 0 订阅
5 篇文章 0 订阅

问题说明来源leetcode

一、问题描述:

122. 买卖股票的最佳时机 II

难度中等1941

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润

示例 1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
     总利润为 4 + 3 = 7 。

示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     总利润为 4 。

示例 3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。

提示:

  • 1 <= prices.length <= 3 * 104
  • 0 <= prices[i] <= 104

二、题解:

思路:

一路下降是没办法的,一路上升还是有机会的。

那么一路上升时,怎么买呢?

对于一路上升,

1、如果我们买开头和结尾的那个来可以吗?

2、如果中间也买再在中间价格售出怎么样?会不会比1方案好?

事实上最好的应该是去峰峰值,在低谷时买到,再在最高点卖出是赚最多的,不管中间买卖了多少挣了多少,也都是比不上开头和结尾的:

在这里插入图片描述

因为手头上最多只能存1个股票,因此每次只能卖出去了才能再买股票。

就算再中间深刻买了很多股票,赚的肯定也是在最大差值以内的,不可能大于最大差值。而就算狠狠地买和卖也不行,因为买了得卖出去才可以买其他的,因此不断买和卖累加的结果是没办法填满最大差值的(最大差值指的是开头结尾买卖赚的)。这一段就是属于上升的

对于一路下降的肯定是不可能的。

于是得到一个假设:最大利润由每段递增坡度的最小买入,最大卖出得到。

当只有一段递增坡度时,肯定是的。那么当只有2段递增坡度呢?也就是中间有一段是递减的,也是对吧。

那么有4段呢?5段呢?n段?

如果n段时这样子可以得到最大利润,那么n+1可以?

证明一下。

当n段可以这么得来,那么n+1段坡度的总最大利润是有前n段递增的坡度加上第n+1段坡度的最大利润得来的。

前n段的总最大利润得到是s(n),第n+1段的最大利润是a(n + 1)

总最大利润s(n + 1)会不会是 s(n) + a(n + 1)呢?

是吗?左边找到总最大的利润s(n)了,再加上右边的那份利润应该是了吧?

而且找到最大利润都是局部最优得到全局最优的,如果砍掉第n+1个坡度,那么最大利润就是s(n)了,如果不砍掉,那么最大利润肯定是增加了,增加了的就是a(n + 1)

每个局部最优组成最大最优,感觉还是有些没论证,因为全局最优不一定等于局部最优累加,在一些特殊的例子里,可能那些例子是会对全局造成了其他影响了,但是这个题就是按照假设的来办就应该没问题了:

/**
 * @author xin麒
 * @date 2023/1/10 18:04
 */
public class Solution {
    public int maxProfit(int[] prices) {
        int res = 0;
        int minNum = 0;
        if (prices.length == 1) return 0;
        int curr = prices[0];
        for (int i = 1; i < prices.length; i++) {
            if (curr > prices[i]){
                //说明是前一个大于后一个,处于递减坡度,找到最小赋予minNum,然后结束;
                while (i < prices.length){
                    if (curr < prices[i]) break;
                    curr = prices[i];
                    i++;
                }
                i--;//如果是最后的递减坡度,那么i此时是len -1
                //找到最小的赋予curr即可
            }else if (curr < prices[i]){
                //说明是递增坡度,
                minNum = curr;
                //找到最大,赋予curr
                while (i < prices.length){
                    if (curr > prices[i]) break;//此时是最大值。(局部)
                    curr = prices[i];
                    i++;
                }
                i--;
                res += curr - minNum;
            }//如果是平谷,那么不用管。
        }
        return res;
    }
}

其实这道题是和376. 摆动序列很像的,曲线都是跌宕起伏的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值