LeetCode每日一题(188. Best Time to Buy and Sell Stock IV)

You are given an integer array prices where prices[i] is the price of a given stock on the ith day, and an integer k.

Find the maximum profit you can achieve. You may complete at most k transactions.

Note: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again).

Example 1:

Input: k = 2, prices = [2,4,1]
Output: 2

Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.

Example 2:

Input: k = 2, prices = [3,2,6,5,0,3]
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.

Constraints:

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

先祝大家中秋快乐。节要过, 题也要做。今天这题确实有些难度,下午三点开始做题,做到现在终于解出来了,不容易。

这题我们先把所有的单调递增区间找出来, 这些区间就是挣钱的区间, 低点买高点卖, 如果区间数量 < k, 那我们就可以认为我们可以拿到所有区间所产生的收益。 但是如果区间数量 > k, 那我们就要考虑这些区间的取舍问题了, 我们要想减少区间的数量有两种方法, 一种是我们干脆放弃这个区间, 另一个是我们将当前这个区间合并到其他区间。 这其实也是我的 dp 方法的核心, 假设 merge(i,j)为合并 ranges[i], ranges[i+1]…ranges[j]为一个区间并计算该区间的收益, dp[i]为从 ranges[i]开始我们可以获得的最大收益, 那 dp[i] = max((merge(i, i) + dp[i+1]), (merge(i, i+1) + dp[i+2]), …, (merge(i, j) + dp[j+1])), 其中 i <= j <= ranges.len()。但是要注意一点,我们的 merge(i, j)并不一定大于 ranges[i]或者 ranges[j]的收益, 也就是说我们合并两个区间并不一定比我们单取某一个区间的收益大, 所以我们也要考虑直接放弃当前区间对后面的区间进行操作的情况。


use std::collections::HashMap;

impl Solution {
    fn dp(
        ranges: &Vec<(i32, i32)>,
        k: i32,
        i: usize,
        cache: &mut HashMap<(usize, i32), i32>,
    ) -> i32 {
        if k == 0 || i == ranges.len() {
            return 0;
        }
        let start = ranges[i].0;
        let mut end = 0;
        let mut ans = 0;
        for j in i..ranges.len() {
            end = end.max(ranges[j].1);
            ans = ans.max(
                end - start
                    + if let Some(c) = cache.get(&(j + 1, k - 1)) {
                        *c
                    } else {
                        Solution::dp(ranges, k - 1, j + 1, cache)
                    },
            );
            ans = ans.max(if let Some(c) = cache.get(&(j + 1, k)) {
                *c
            } else {
                Solution::dp(ranges, k, j + 1, cache)
            });
        }
        cache.insert((i, k), ans);
        ans
    }
    pub fn max_profit(k: i32, prices: Vec<i32>) -> i32 {
        if prices.is_empty() {
            return 0;
        }
        let mut ranges = Vec::new();
        let mut start = prices[0];
        let mut end = prices[0];
        for p in prices.into_iter().skip(1) {
            if p < end {
                if start != end {
                    ranges.push((start, end));
                }
                start = p;
                end = p;
                continue;
            }
            end = p;
        }
        if start != end {
            ranges.push((start, end));
        }
        Solution::dp(&ranges, k, 0, &mut HashMap::new())
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值