Back
Featured image of post Stocks股票问题

Stocks股票问题

在?看看炒股?你看那片天绿不绿啊?

股票问题

我们需要注意的是交易次数k的限制


121. 买卖股票的最佳时机 股票入门题目

只有一次交易机会,我们只需要找到最小价格日和最大价格日即可解决问题

    //交易次数k的限制
    //k = 1
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int profit = 0, buy = prices[0];
        for (int i = 1; i < n; i++) {
            profit = Math.max(profit, prices[i] - buy);
            buy = Math.min(buy, prices[i]);
        }
        return profit;
    }

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

122则可以进行多次交易,我们需要用dp状态机来解决问题

  • dp[i][0]表示未持有股票

  • dp[i][1]表示持有股票

    dp[i][0]状态则从前一天的(未持有 ,持有卖出)转移 ,

    dp[i][1]状态则从前一天的(持有,未持有买入)转移

	//k = +infinity
    public int maxProfitDP(int[] prices) {
        int n = prices.length;
        int[][] dp = new int[n][2];
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        for (int i = 1; i < n; i++) {
            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]);
        }
        return dp[n - 1][0];
    }

	//对二维dp进行优化
	//每一天的情况只与前一天的有关
    public int maxProfit_k_inf(int[] prices){
        int n = prices.length;
        if (n == 0){
            return 0;
        }
        int dp0 = 0, dp1 = -prices[0];
        for (int price : prices) {
            dp0 = Math.max(dp0, dp1 + price);
            dp1 = Math.max(dp1, dp0 - price);
        }
        return dp0;
    }

	//我们注意到题目要求也符合贪心算法
    public int maxProfit(int[] prices) {
        //只要有赚就卖
        int n = prices.length;
        int profit = 0;
        for (int i = 1; i < n; i++) {
            profit += Math.max(0, prices[i] - prices[i - 1]);
        }
        return profit;
    }

714. 买卖股票的最佳时机含手续费

无限次交易,需计算手续费进行判断

我们只需在121的基础上进行修改就好

	//k with fee
    public int maxProfit_k_fee(int[] prices , int fee){
        int n = prices.length;
        int profit = 0, buy = -prices[0];
        for (int i = 1; i < n; i++) {
            profit = Math.max(profit, prices[i] + buy - fee);
            buy = Math.max(buy, profit - prices[i]);
        }
        return profit;
    }

309. 最佳买卖股票时机含冷冻期

每次交易后都会有一天的冷冻期才可以进行下一次交易,即有三种状态:未持有,冷冻期,持有

用dp状态机去解决不同0 / 1 / 2三种情况

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n == 0) {
            return 0;
        }
        //0:持股,1:卖出进入CD, 2:不持股且不CD
        int[][] dp = new int[n][3];
        dp[0][0] = -prices[0];
        for (int i = 1; i < n; i++) {
            //买入,前者是状态1持股未卖出 , 后者是处于状态2的时候准备卖出
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2] - prices[i]);
            //今天卖了,收益是↓
            dp[i][1] = dp[i - 1][0] + prices[i];
            //dp[i - 1][1]股票之前就卖掉了,前一天是冷冻期 , 后者则是之前卖了且前一天不在CD
            dp[i][2] = Math.max(dp[i - 1][1], dp[i - 1][2]);
        }

        return Math.max(dp[n - 1][1], dp[n - 1][2]);
    }

	//优化
	//k with cooldown
    public int maxProfit_k_cd(int[] prices){
        int n = prices.length;
        if (n == 0){
            return 0;
        }
        //dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
        //dp[i][1] = max(dp[i-1][1], dp[i-2][0] - prices[i])
        //dp[i][]只与dp[i - 1][]有关 , 用pre去代替
        int dp_i_0 = 0 , dp_i_1 = Integer.MIN_VALUE , dp_pre_0 = 0;
        for (int price : prices) {
            int tmp = dp_i_0;
            dp_i_0 = Math.max(dp_i_0, dp_i_1 + price);
            dp_i_1 = Math.max(dp_i_1, dp_pre_0 - price);
            dp_pre_0 = tmp;
        }
        return dp_i_0;
    }

123. 买卖股票的最佳时机 III

规定交易次数k = 2

    //k = 2
    public int maxProfit_k_2(int[] prices){
        int n = prices.length;
        if (n == 0){
            return 0;
        }
        int dp_i_1_0 = 0 , dp_i_1_1 = Integer.MIN_VALUE , dp_i_2_0 = 0 , dp_i_2_1 = Integer.MIN_VALUE;
        for (int price : prices){
            dp_i_2_0 = Math.max(dp_i_2_0 , dp_i_2_1 + price);
            dp_i_2_1 = Math.max(dp_i_2_1 , dp_i_1_0 - price);
            dp_i_1_0 = Math.max(dp_i_1_0 , dp_i_1_1 + price);
            dp_i_1_1 = Math.max(dp_i_1_1 , -price);
        }
        return dp_i_2_0;
    }

188. 买卖股票的最佳时机 IV

规定交易次数为k ,123的延伸版本

    //k = any integer
    public int maxProfit_k(int[] prices , int max_K){
        int n = prices.length;
        if (n == 0){
            return 0;
        }else if (n / 2 < max_K){
            //若k > n / 2 ,即相当于可以进行无数次交易
            return maxProfit_k_inf(prices);//122
        }

        //n股票天数
        //max_k交易次数
        //0未持有/1持有
        int[][][] dp = new int[n][max_K + 1][2];

        //initialize
        for (int i = 0; i <= max_K ; i++) {
            dp[0][i][1] = -prices[0];
        }

        for (int i = 1; i < n; i++) {
            for (int j = 1; j <= max_K ; j++) {
                dp[i][j][0] = Math.max(dp[i - 1][j][0] , dp[i - 1][j][1] + prices[i]);
                dp[i][j][1] = Math.max(dp[i - 1][j][1] , dp[i - 1][j - 1][0] - prices[i]);
            }
        }
        return dp[n - 1][max_K][0];
    }
Welcome to the world of Minezeratul