剑指 offer第63题-股票的最大利润

可以有一次买入和一次卖出,买入必须在前。求最大收益。

在这里插入图片描述
使用贪心策略,假设第 i 轮进行卖出操作,买入操作价格应该在 i 之前并且价格最低。

Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Not 7-1 = 6, as selling price needs to be larger than buying price.

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

状态:一次买buy,一次卖sell,买则损失-price[i],卖则增加price[i]
收益=buy+price[i],buy默认为负数

buy=max(buy, -price[i])
sell=max(sell, buy+price[i])

第一天买的话,buy=-price[0],sell=0, 返回sell

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length<=1)
            return 0;
        int buy=-prices[0],sell=0;
        for(int i=1;i<prices.length;i++){
            buy=Math.max(buy,-prices[i]);
            sell=Math.max(sell,buy+prices[i]);
        }
        return sell;
    }
}

二、买股票二,可以无限次买入卖出

Input: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
engaging multiple transactions at the same time. You must sell before buying again.

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

因为可以无限次买入卖出,则buy和sell之间就要比较

转移方程为:
buy=Math.max(buy, sell-price[i])
sell=Math.max(sell, buy+price[i])

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length<=1) return 0;
        int buy=-prices[0],sell=0;
        for(int i=1;i<prices.length;i++){
            buy=Math.max(buy,sell-prices[i]);
            sell=Math.max(sell, buy+prices[i]);
        }
        return sell;
    }
}

三、最多两笔交易,两次买,两次卖,求最大收益

Input: [3,3,5,0,0,3,1,4]
Output: 6
Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
engaging multiple transactions at the same time. You must sell before buying again.

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

转移方程为:
第一次买卖:
fstBuy=Math.max(fstBuy, -price[i])
fstSell=Math.max(fstSell, fstBuy+price[i])
第二次买卖,受到第一次买卖的影响:
secBuy=Math.max(secBuy, fstSell-price[i])
secSell=Math.max(secSell, secBuy+price[i])

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length<=1) return 0;
        int fstBuy=Integer.MIN_VALUE,fstSell=0;
        int secBuy=Integer.MIN_VALUE,secSell=0;
        for(int i=0;i<prices.length;i++){
            fstBuy=Math.max(fstBuy,-prices[i]);
            fstSell=Math.max(fstSell,fstBuy+prices[i]);
            
            secBuy=Math.max(secBuy,fstSell-prices[i]);
            secSell=Math.max(secSell,secBuy+prices[i]);
        }
        return secSell;
    }
}

四、买股票四,增加参数k,限制最多k次交易:

Input: [2,4,1], k = 2
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.

Input: [3,2,6,5,0,3], k = 2
Output: 7
Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4.
Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.

k>=|prices| / 2,实际上相当于不限制交易次数
k<|prices|/2,循环的次数限制在k里面

class Solution {
    public int maxProfit(int k, int[] prices) { // TLE
        if (prices.length <= 1)
            return 0;
 
        // 假设|prices| == 4, 那么你顶多能做两次交易,如果k >= prices.length / 2,实际上就相当于不限制交易次数了
        if (k >= prices.length / 2) {
            int res = 0;
 
            for (int i = 1; i < prices.length; i++) {
                if (prices[i] > prices[i - 1]) {
                    res += prices[i] - prices[i - 1];
                }
            }
 
            return res;
        } else {
            int[][] dp = new int[2][prices.length];
 
            for (int i = 1; i <= k; i++) {
                int tmpMax = dp[(i - 1) % 2][0] - prices[0];
 
                for (int j = 1; j < prices.length; j++) {
                    dp[i % 2][j] = Math.max(dp[i % 2][j - 1], tmpMax + prices[j]);
                    tmpMax = Math.max(tmpMax, dp[(i - 1) % 2][j] - prices[j]);
                }
            }
 
            return Math.max(dp[0][prices.length - 1], dp[1][prices.length - 1]);
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值