动态规划股票题(全)

第一个就是经典的股票问题,我们有一系列的股票信息,只能买卖一次求最大的收益

1.假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?

思路:
首先分析一下题目找出题目中所求的是什么,我们要找到的是最大的收益也就是买入和卖出那天的整数变量的差值。那么我们要找的就是最后一天所能拥有的最大利益。我们的dp数组的含义就可以设置为在第index天所能拥有的最大利益。
接下来我们分析我们在第index天有多少种状态:第一个是持有股票状态,第二个就是为持有股票状态。
那么我们的dp就是一个一维数组dp[prices,length][2];
接下来是状态变化方程:

很明显持有股票状态是等于-prices[index]的,第二个未持有股票状态也就是前一天持有股票的值(买入股票后的负值)加上今天的票价。
dp[i][0] = math.max(dp[i-1][0],-prices[I]);
dp[i][1] = math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
这个状态变化
这样再来保持一个循环不变式的成立(算导第1部分第2章)
初始化:确保dp[0][1]是我在第一天的股票购入状态所能有的最大值而dp[0][1]则是我在第一天为持有股票状态的最大值。
int[][] dp = new int[prices.length][2];
dp[0][0] = -prices[0];
dp[0][1] = 0;
循环状态:在每一次循环开始前我们都保存了前一天所能有的两个状态的最大值,在到下一天去找这样一个最大值
for(int i=1;i

​ dp[i][0] = dp[i-1][0]>-prices[i]?dp[i-1][0]:-prices[i];

​ dp[i][1] = dp[i-1][1]>dp[i][0]+prices[i]?dp[i-1][1]:dp[i][0]+prices[i];

​ }
结束状态:在这个状态我们通过前面的循环得到了最后一天的两个状态的最大值而其中的dp[prices.length-1][1]就是我们想要的结果。

//第一种动态规划代码
 public int maxProfit(int[] prices) {if(prices.length==0||prices.length==1) return 0;int[][] dp = new int[prices.length][2];

​    dp[0][0] = -prices[0];

​    dp[0][1] = 0;for(int i=1;i<prices.length;i++){

​      dp[i][0] = dp[i-1][0]>-prices[i]?dp[i-1][0]:-prices[i];

​      dp[i][1] = dp[i-1][1]>dp[i][0]+prices[i]?dp[i-1][1]:dp[i][0]+prices[i];}return dp[prices.length-1][1];

  }
/**
//这里对刚刚所分析的状态保存数组来压缩一下
//可以将每一天的买入状态保存在一个整形变量中那么dp数组就可以
//是一维数组、代码如下
//同理也可以不使用数组直接保存最小值状态两个整形
**/
public int maxProfit(int[] prices) {if(prices.length==0) return 0;int[] dp = new int[prices.length];int min = prices[0];for(int i=1;i<prices.length;i++){

​      min = min<prices[i]?min:prices[i];

​      dp[i] = dp[i-1]>(prices[i]-min)?dp[i-1]:(prices[i]-min);}return dp[prices.length-1];

  }

2.给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

这个题目则是没有限制交易次数

依旧状态还是两个第一个是所在的天数,第二个是股票的持有
这样状态变化就是 持有股票->未持有股票(0代表持有)
dp[i][0] = math.max(dp[i-1][0],dp[i-1][1]-prices[i]);
dp[i][1] = math.max(dp[i-1][1],dp[i-1][0]+prices[I]);
与之前不同的地方就是我们这次可以多次买入和卖出,那么在买入股票的位置需要与前一天的买入状态比较保留一个最大的,卖出状态变化规律依旧不变

这道题也可以使用贪心算法来计算。

public int maxProfit(int[] prices) {if(prices.length==0) return 0;int[][] dp = new int[prices.length][2];

​    dp[0][0] = -prices[0];

​    dp[0][1] = 0;for(int i=1;i<prices.length;i++){

​      dp[i][0] = dp[i-1][0]>dp[i-1][1]-prices[i]?dp[i-1][0]:dp[i-1][1]-prices[i];

​      dp[i][1] = dp[i-1][1]>dp[i-1][0]+prices[i]?dp[i-1][1]:dp[i-1][0]+prices[i];}return dp[prices.length-1][1];

  }

3.给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

这道题要求仅仅可以完成两笔交易那么就多出了一个状态,就是当前天数的当天状态完成了1次交易或者两次交易,这个交易次数也是一个影响当前最优状态的一个变化量
那么dp就是一个三维数组了
dp[prices.length][2][2]
状态变化:第一次持有状态->第一次未持有状态->第二次持有状态->第二次未持有状态
最后返回最后一天中第一次未持有和第二次未持有中最大的那个
变化方程:
dp[i][0][0] = Math.max(dp[i-1][0][0],-prices[i]);
dp[i][1][0] = Math.max(dp[i-1][1][0],dp[i][0][0]+prices[i]);
dp[i][0][1] = Math.max(dp[i-1][0][1],dp[i-1][1][0]-prices[i]);
dp[i][1][1] = Math.max(dp[i-1][1][1],dp[i-1][0][1]+prices[i]);

//第一次持有状态->第一次未持有状态->第二次持有状态->第二次未持有状态
    public int maxProfit(int[] prices) {
        if(prices.length==0) return 0;
        if(prices.length==0) return 0;
        int[][][] dp = new int[prices.length][2][2];
        dp[0][0][0]=-prices[0];//第一次持有状态
        dp[0][1][0]=0;//第一次未持有状态
        dp[0][0][1] = Integer.MIN_VALUE;//第二次持有状态
        dp[0][1][1] = Integer.MIN_VALUE;//第二次未持有状态
        for(int i=1;i<prices.length;i++){
            dp[i][0][0] = Math.max(dp[i-1][0][0],-prices[i]);
            dp[i][1][0] = Math.max(dp[i-1][1][0],dp[i][0][0]+prices[i]);
            dp[i][0][1] = Math.max(dp[i-1][0][1],dp[i-1][1][0]-prices[i]);
            dp[i][1][1] = Math.max(dp[i-1][1][1],dp[i-1][0][1]+prices[i]);
        }
        return Math.max(dp[prices.length-1][1][1],dp[prices.length-1][1][0]);
    }

4.给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。

注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
这道题相对于前一道题来说限制更小了但是相对应的状态的变化情况就会变多了
这里我们的dp的最后一个维度就会变大变成[k]
dp[prices.length][2][k]
循环中的便利次数也会增加变成n*k之前分别是2n和n
这里直接贴出代码,这个思路和前一个题基本一致

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

你可能感兴趣的:(算法,算法,java,动态规划)