Best Time to Buy and Sell Stock IV

LeetCode problem 188. Best Time to Buy and Sell Stock IV.

## Problem description

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`

## Problem analysis

We can borrow the idea from the problem Best Time to Buy and Sell Stock III, in which we can do at most 2 transactions. But in this problem, we can do at most *k* transactions.

On each day, we can choose to take one of the following actions:

* **Do nothing.** In this case both the balance and the profit at our hand do not change.
* **Buying a new stock.** After this action the balance at our hand would be the profit we have earned on all previous days minus the price of the day. Hence, if we want to buy a new stock today, we want to make the profit we have earned on previous days as large as possible. (*Not applicable on the last day*)
* **Selling the stock.** After this action our profit would be the balance at our hand plus the stock price of the day. The greater balance we have at hand, the greater the profit would be. (*Not applicable on the first day; applicable only if we have a stock at hand*)

So for each day, we have to keep track of:

* **Possible maximal balance** after we have completed 0.5, 1.5, 2.5, …, (*k* - 0.5) transactions.
* **Possible maximal profit** after we have completed 1, 2, 3, …, *k* transactions.

To do this, we create two arrays:

1. `balance`, with *k* elements initialized to `INT_MIN`. For each day, `balance[i]` represents the maximum balance we could have at hand after we have completed (*i* + 0.5) transactions on that day.
2. `maxProfit`, with *k* elements initialized to 0. For each day, `maxProfit[i]` represents the maximum profit we could have at hand after we have completed (*i* + 1) transactions on that day.

Then we can iterate through all the prices in *one-pass*. For each day's `price`, and for each *i* in 0 through *k* - 1, we do the following:

1. Update `balance[i]`.
	* If *i* = 0, then `balance[i] = std::max(balance[i], -price)`.
	* If *i* > 0, then `balance[i] = std::max(balance[i], maxProfit[i-1] - price)`.
		+ `balance[i]` means we do not buy a new stock on the day.
		+ `-price` or `maxProfit[i-1] - price` means we do buy a new stock on the day.
2. Update `maxProfit[i]`.
	* `maxProfit[i] = std::max(maxProfit[i], balance[i] + price)`.
		+ `maxProfit[i]` means we do not sell the stock at hand on the day.
		+ `balance[i] + price` means we do sell the stock on the day.

After going through all the iterations, return `maxProfit[k-1]` as the result.

### Working example

* Input: [3, 4, 1, 2, 6, 2, 3, 5, 1, 7, 3, 8], *k* = 4

* Return: **19**
	1. Buy on day 2 → sell on day 4 (profit: 5; total profit: 5)
	2. Buy on day 5 → sell on day 7 (profit: 3; total profit: 8)
	3. Buy on day 8 → sell on day 9 (profit: 6; total profit: 14)
	4. Buy on day 10 → sell on day 11 (profit: 5; total profit: 19)

### Complexity analysis

Time complexity
The outer loop takes O(*n*) time to iterate through, where *n* is the number of days.
The inner loop takes O(*k*) time each to iterate through, to update the `balance` and `maxProfit` arrays.
So the total time complexity is **O(*n* ⋅ *k*)**.
Space complexity
Since we only created two arrays `balance` and `maxProfit` for iterations, and each array has exactly *k* elements, the total space complexity is **O(*k*)**.
## Solution

### C++ solution

```
class Solution {
public:
 int maxProfit(int k, const std::vector<int>& prices) {
 if ((k == 0) || (prices.size() < 2)) {
 return 0;
 }

 // balance: keep track of maximum balance after 0.5, 1.5, 2.5, ...
 // transactions
 std::vector<int> balance(k, INT\_MIN);
 // maxProfit: keep track of maxProfit after 1, 2, 3, ... transactions
 std::vector<int> maxProfit(k, 0);

 for (const int& price: prices) {
 for (int i = 0; i < k; ++i) {
 balance[i] = std::max(balance[i],
 (i == 0 ? 0 : maxProfit[i-1]) - price);
 maxProfit[i] = std::max(maxProfit[i], balance[i] + price);
 }
 }

 return maxProfit[k - 1];
 }
};

```

### Java solution

```
class Solution {
 public int maxProfit(int k, int[] prices) {
 if ((k == 0) || (prices.length < 2)) {
 return 0;
 }

 // balance: keep track of maximum balance after 0.5, 1.5, 2.5, ...
 // transactions
 int[] balance = new int[k];
 Arrays.fill(balance, Integer.MIN\_VALUE);
 // maxProfit: keep track of maxProfit after 1, 2, 3, ... transactions
 int[] maxProfit = new int[k];

 for (int price: prices) {
 for (int i = 0; i < k; ++i) {
 balance[i] = Integer.max(balance[i],
 (i == 0 ? 0 : maxProfit[i-1]) - price);
 maxProfit[i] = Integer.max(maxProfit[i], balance[i] + price);
 }
 }

 return maxProfit[k - 1];
 }
}

```

## See also

Best time to buy and sell stock
 122
 123
 188
 309
 714