动态规划示例——以leetcode股票系列问题为例

动态规划是编程题中高频出现,且具有一定难度的算法。对于动态规划的解读参见本篇博客。下面我们以leetcode中的股票问题为例,使用动态规划算法解决问题。

leetcode121

在这里插入图片描述
根据题意可以知道,我们只能买卖一次股票,为了使得股票利润最大,我们可以推导得出如下方程。设 d p [ i ] [ 0 ] dp[i][0] dp[i][0]为第 i i i天买入股票后剩余的钱, d p [ i ] [ 1 ] dp[i][1] dp[i][1]为卖出股票后剩余的钱。我们的目的则是,让买入股票后剩余的钱尽可能多,卖出股票后获取钱尽可能多。所以可以得到状态转移方程:
d p [ i + 1 ] [ 1 ] = m a x ( d p [ i ] [ 1 ] , d p [ i ] [ 0 ] + p r i c e s [ i + 1 ] ) dp[i+1][1]=max(dp[i][1],dp[i][0]+prices[i+1]) dp[i+1][1]=max(dp[i][1],dp[i][0]+prices[i+1])
d p [ i + 1 ] [ 0 ] = m a x ( d p [ i ] [ 0 ] , − p r i c e s [ i + 1 ] ) dp[i+1][0]=max(dp[i][0],-prices[i+1]) dp[i+1][0]=max(dp[i][0],prices[i+1])

初始时, d p [ 0 ] [ 0 ] = − p r i c e s [ 0 ] , d p [ 0 ] [ 1 ] = 0 dp[0][0]=-prices[0],dp[0][1]=0 dp[0][0]=prices[0]dp[0][1]=0
所以,代码如下:

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

但是我们实际上只需要保留上一天的买入股票剩余的钱与卖出股票获得的钱即可,对代码进行优化,令 c a s h = d p [ i ] [ 1 ] , h o l d = d p [ i ] [ 0 ] cash=dp[i][1],hold=dp[i][0] cash=dp[i][1]hold=dp[i][0]

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

leetcode 122

在这里插入图片描述
根据题意我们可以知道,现在股票可以多次买入卖出。根据这个新特点,我们重新设计状态转移方程:
d p [ i + 1 ] [ 1 ] = m a x ( d p [ i ] [ 1 ] , d p [ i ] [ 0 ] + p r i c e s [ i + 1 ] ) dp[i+1][1]=max(dp[i][1],dp[i][0]+prices[i+1]) dp[i+1][1]=max(dp[i][1],dp[i][0]+prices[i+1])
d p [ i + 1 ] [ 0 ] = m a x ( d p [ i ] [ 0 ] , d p [ i ] [ 1 ] − p r i c e s [ i + 1 ] ) dp[i+1][0]=max(dp[i][0],dp[i][1]-prices[i+1]) dp[i+1][0]=max(dp[i][0],dp[i][1]prices[i+1])
初始状态与上面相同,令 c a s h = d p [ i ] [ 1 ] , h o l d = d p [ i ] [ 0 ] cash=dp[i][1],hold=dp[i][0] cash=dp[i][1]hold=dp[i][0],对代码进行优化后得到:

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

leetcode 714

在这里插入图片描述
此题与122题基本一样,我们可以认定,股票不会再同一天买入然后卖出,因为这样必然会亏本(扣除手续费fee)。所以状态转移方程可以确定为:
d p [ i + 1 ] [ 1 ] = m a x ( d p [ i ] [ 1 ] , d p [ i ] [ 0 ] + p r i c e s [ i + 1 ] − f e e ) dp[i+1][1]=max(dp[i][1],dp[i][0]+prices[i+1]-fee) dp[i+1][1]=max(dp[i][1],dp[i][0]+prices[i+1]fee)
d p [ i + 1 ] [ 0 ] = m a x ( d p [ i ] [ 0 ] , d p [ i ] [ 1 ] − p r i c e s [ i + 1 ] ) dp[i+1][0]=max(dp[i][0],dp[i][1]-prices[i+1]) dp[i+1][0]=max(dp[i][0],dp[i][1]prices[i+1])
同样,将代码优化, c a s h = d p [ i ] [ 1 ] , h o l d = d p [ i ] [ 0 ] cash=dp[i][1],hold=dp[i][0] cash=dp[i][1]hold=dp[i][0],得到

class Solution {
    public int maxProfit(int[] prices, int fee) {
        int cash=0,hold=-prices[0];
        for(int i=0;i<prices.length;i++){
            cash=Math.max(cash,hold+prices[i]-fee);
            hold=Math.max(hold,cash-prices[i]);
        }
        return cash;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值