LeetCode 188. Best Time to Buy and Sell Stock IV(动态规划)

本博客介绍LeetCode 188题目的解法,该题要求在给定股票价格数组中找到最大利润,但限制了最多可进行k次交易。采用动态规划思路,通过状态压缩优化算法复杂度至O(nk),并讨论当k大于股票天数一半时的特殊情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来源:https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/

问题描述

188. Best Time to Buy and Sell Stock IV

Hard

Say you have an array for which the ithelement is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete at most ktransactions.

Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

Example 1:

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.

Example 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.

------------------------------------------------------------

题意

给定一个价格序列prices和一个正整数k,k表示可以在这个价格序列上进行的交易次数的最大值(一次交易包括一次买入行为+一次卖出行为,可以在同一个时刻既买入又卖出)。求最大获利?

------------------------------------------------------------

思路

动态规划dp[i][j]表示截止到第j个月最多进行i次交易的最大获利(不一定要在第j个月有发生交易)。递推关系为:

dp[i][j] = max(dp[i-1][u] + prices[j] – prices[u]), u <= j

由于dp[i][]仅仅与dp[i-1][]有关,因此可以状态压缩将一个二维动态规划数组变成两个一维动态规划数组。

这样的算法时间复杂度是O(n^2*k)的。可以进一步优化时间复杂度为O(nk). 注意到在j从1向n-1遍历的过程中,dp[i-1][u] – prices[u]有平方级别的重复计算,因此考虑用变量localMax维护dp[i-1][u] – prices[u],在计算dp[i][j]的同时更新localMax. 递归式组为:

dp[i][j] = max(cur[i][j-1], localMax + prices[j])

localMax = max(localMax, dp[i-1][j] - prices[j])

还有一个与动态规划无关但是可以优化的点是当k>n/2时,实际上没有了交易次数的限制,因为最大的交易次数的限制就是n/2,因此可以直接用O(n)算法算出最大获利,无需使用动态规划

------------------------------------------------------------

代码

class Solution {
    public int maxProfit(int k, int[] prices) {
        int n = prices.length;
        if (n == 0 || k == 0) {
            return 0;
        }
        if (k > n/2) {
            int ans = 0;
            for (int i=1; i<n; ++i) {
                ans += prices[i] > prices[i-1]? prices[i] - prices[i-1]: 0;
            }
            return ans;
        }
        int[] pre = new int[n], cur = new int[n];
        int localMax = 0;
        for (int i=0; i<k; ++i) {
            localMax = pre[0] - prices[0];
            for (int j=1; j<n; ++j) {
                cur[j] = Math.max(cur[j-1], localMax + prices[j]);
                localMax = Math.max(localMax, pre[j] - prices[j]);
            }
            pre = Arrays.copyOf(cur, n);
        }
        return cur[n-1];
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值