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())
}
}