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

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

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

力扣题目链接(opens new window)

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

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

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

  • 示例 1:
  • 输入:prices = [3,3,5,0,0,3,1,4]
  • 输出:6 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3。
  • 示例 2:
  • 输入:prices = [1,2,3,4,5]
  • 输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
  • 示例 3:
  • 输入:prices = [7,6,4,3,1]
  • 输出:0 解释:在这个情况下, 没有交易完成, 所以最大利润为0。
  • 示例 4:
  • 输入:prices = [1] 输出:0

提示:

  • 1 <= prices.length <= 10^5
  • 0 <= prices[i] <= 10^5

思路

 思路:动态规划
 第一次做这道题,真想不到如何定义dp数组
 1.dp数组以及下标代表含义
 定义二维dp数组dp[i][j] i表示在第i天最大的利益
 一天一共五个状态
 j = 0 没有持有股票
 j = 1 第一次持有股票
 j = 2 第一次持有股票后卖出
 j = 3 第二次持有股票
 j = 4 第二次持有股票后卖出
 因为题目要求最多可买卖两次,当第二次持有股票时,需要知道【第一次持有股票】和【第一次持有股票卖出后】的状态
 而之前的股票题目要么是完全不限制次数,要么只有一次,因此将【第一次持有股票卖出后】的状态和【没有持有股票】作为一个状态。需要注意下区分
 2.确定递推公式
 第一次持有股票 dp[i][1] = Math.max( dp[i-1][1] , -prices[i])
 第一次持有股票后卖出 dp[i][2] = Math.max( dp[i-1][2] , dp[i-1][1] + prices[i])
 第二次持有股票 dp[i][3] = Math.max( dp[i-1][3] ,dp[i-1][2] -prices[i])
 第二次持有股票后卖出 dp[i][4] = Math.max( dp[i-1][4] , dp[i-1][3] + prices[i])
 3.dp数组初始化
 dp[0][0] = 0;
 dp[0][1] = -prices[0];
 dp[0][2] = 0 可以理解当天买入,当天卖出,所以dp[0][2] = 0;
 dp[0][3] = -prices[i] 可以理解当天买入,当天卖出,再次买入
 dp[0][4] = 0
 4.遍历顺序,dp[i]由dp[i-1]推导,故正序
 5.举例推导dp数组

 由递推公式
 时间复杂度o(n)
 空间复杂度o(5*n)

代码如下

public static int maxProfitIII(int[] prices) {
    if (prices == null || prices.length == 0)
        return 0;
    int[][] dp = new int[prices.length][5];
    dp[0][0] = 0;
    dp[0][1] = -prices[0];
    dp[0][3] = -prices[0];
    for (int i = 1; i < prices.length; i++) {
        dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
        dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
        dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
        dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]);

    }
    return Math.max(dp[prices.length - 1][2], dp[prices.length - 1][4]);
}

问题

问题
采用了错误的思路

思路:贪心
将利润拆分为(第二天 - 第一天),(第三天 - 第二天) 。。。。
将正利润累加,并存放在List中,求出利润最大的两项。
这种拆分利润的方式适用于求交易不限情况
无法通过此测试用例

输入:[1,2,4,2,5,7,2,4,9,0]
输出:12
预期结果:13

list 中的结果 为3,5,7.那么其中两个最大的数字选择5 +7 =12作为结果
但测试用例中存在更大的利润组合
比如7-1 = 6,9-2 = 7
两者组合等于13
所以此思路不通过

错误代码如下

public static int maxProfitIII(int[] prices) {
    if (prices == null || prices.length == 0)
        return 0;
    int sum = 0;
    List<Integer> profits = new LinkedList<>();
    for (int i = 1; i < prices.length; i++) {
        if (prices[i] - prices[i - 1] >= 0) {
            sum = sum + prices[i] - prices[i - 1];
            if (i == prices.length - 1)
                profits.add(sum);
        } else {
            profits.add(sum);
            sum = 0;
        }

    }

    int maxProfit = 0;// 最大利润
    int minProfit = 0;
    for (int i = 0; i < profits.size(); i++) {
        if (profits.get(i) > maxProfit) {
            minProfit = maxProfit;
            maxProfit = profits.get(i);
        } else if (profits.get(i) > minProfit) {
            minProfit = profits.get(i);
        }
    }
    return maxProfit + minProfit;
}

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

力扣题目链接(opens new window)

给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。

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

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

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

提示:

  • 0 <= k <= 100
  • 0 <= prices.length <= 1000
  • 0 <= prices[i] <= 1000

思路

思路:动态规划
1.dp数组以及下标代表含义
定义二维dp数组dp[i][j] i表示在第i天最大的利益
一天一共2k + 1个状态
j = 0 没有持有股票
j = 1 第一次持有股票
j = 2 第一次持有股票后卖出
j = 3 第二次持有股票
j = 4 第二次持有股票后卖出
.....
j = 2*k -1 第k次持有股票
j = 2*k 第k次持有股票后卖出
2.确定递推公式
第一次持有股票 dp[i][1] = Math.max( dp[i-1][1] , -prices[i])
第一次持有股票后卖出 dp[i][2] = Math.max( dp[i-1][2] , dp[i-1][1] + prices[i])
第二次持有股票 dp[i][3] = Math.max( dp[i-1][3] ,dp[i-1][2] -prices[i])
第二次持有股票后卖出 dp[i][4] = Math.max( dp[i-1][4] , dp[i-1][3] + prices[i])
以此类推
3.dp数组初始化
dp[0][0] = 0;
dp[0][1] = -prices[0];
dp[0][2] = 0 可以理解当天买入,当天卖出,所以dp[0][2] = 0;
dp[0][3] = -prices[i] 可以理解当天买入,当天卖出,再次买入
dp[0][4] = 0
....以此类推
4.遍历顺序,dp[i]由dp[i-1]推导,故正序
5.举例推导dp数组

由递推公式
时间复杂度o(n * k)
空间复杂度o(n * k)

代码如下

public static void main(String args[]) {
    int k = 2;
    int[] prices = new int[]{3, 2, 6, 5, 0, 3};
    maxProfit(k, prices);
}

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

    for (int i = 1; i < prices.length; i++) {

        for (int j = 1; j <= k; j++) {
            dp[i][2 * j - 1] = Math.max(dp[i - 1][2 * j - 1], dp[i - 1][2 * j - 2] - prices[i]);
            dp[i][2 * j] = Math.max(dp[i - 1][2 * j], dp[i - 1][2 * j - 1] + prices[i]);
        }
    }
    return dp[prices.length - 1][2 * k];
}

你可能感兴趣的:(算法,数据结构,leetcode,排序算法,java)