Best Time to Buy and Sell Stock with Cooldown

LeetCode problem 309. Best Time to Buy and Sell Stock with Cooldown.

## Problem description

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

Find the maximum profit you can achieve. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times) with the following restrictions:

* After you sell your stock, you cannot buy stock on the next day (i.e., cooldown one day).

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

Example 1
**Input:** prices = [1,2,3,0,2]
**Output:** 3
**Explanation:** transactions = [buy, sell, cooldown, buy, sell]
Example 2
**Input:** prices = [1]
**Output:** 0
Constraints
* `1 <= prices.length <= 5000`
* `0 <= prices[i] <= 1000`

## Problem analysis

This problem is similar to the problem Best Time to Buy and Sell Stock II in that we can make *unlimited number* of transactions. However, in this problem, there is a cool-down day after each selling of stock before you can purchase another stock.

So we can use two arrays:

1. **`balance`**, to keep track of the maximum balance you can have at hand on each day. `balance[i]` means the maximum amount at hand on day *i* after you have made 0.5, 1.5, 2.5, … transactions. For each iteration, we want to make `balance[i]` *as high as possible*.
2. **`maxProfit`**, to keep track of the maximum profit you can have at hand on each day. `maxProfit[i]` means the maximum profit you can gain on day *i* regarding all possible combinations of purchases and sales.

We can iterate from day 0 to day *n*-1 through all the prices. On each day *i* we will update `balance[i]` and `maxProfit[i]` as follows:

* For `i == 0`:
	1. `balance[i] = -price[i]`
	2. `maxProfit[i] = 0`
* For `i == 1`:
	1. `balance[i] = max(balance[0], -prices[i])`
	2. `maxProfit[i] = max(0, prices[1] - prices[0])`
* For `i >= 2`:
	1. `balance[i] = max(balance[i-1], maxProfit[i-2] - prices[i])`
		+ `balance[i-1]`: The balance on day *i* if you do not buy stock on this day.
		+ `maxProfit[i-2] - prices[i]`: The balance on day *i* if you do buy stock on this day. Note that since there is a cool-down period, we can only consider the maximum profit made two days ago.
	2. `maxProfit[i] = max(maxProfit[i-1], balance[i-1] + prices[i])`
		+ `maxProfit[i-1]`: The balance on day *i* if you do not sell stock on this day.
		+ `balance[i-1] + prices[i]`: The balance on day *i* if you do buy stock on this day.

After iterating through all the days, `maxProfit[n-1]` will be the result.

### Working example

* Input: 5, 1, 2, 3, 7, 2, 5, 1, 3

 `balance` (after each iteration)
 `maxProfit` (after each iteration)

* Return: **8**
	1. Buy on day 1 → sell on day 4 (profit: 6)
	2. Buy on day 7 → sell on day 8 (profit: 2)

### Complexity analysis

Time complexity
Since we iterate through each day once, and the computation amount is constant for each single day, the total time complexity is **O(n)**, where *n* is the total number of days.
Space complexity
Since we created two arrays for `balance` and `profit`, each with *n* elements, where *n* is the total number of days, the total space complexity is **O(n)**.
## Solution

### C++ solution

```
class Solution {
public:
 int maxProfit(std::vector<int>& prices) {
 const int len = prices.size();
 if (len <= 1) {
 return 0;
 }
 else if (len == 2) {
 return std::max(0, prices[1] - prices[0]);
 }

 // len >= 3
 int balance[len], maxProfit[len];
 memset(balance, INT\_MIN, sizeof(balance));
 memset(maxProfit, 0, sizeof(maxProfit));

 balance[0] = -prices[0];

 balance[1] = std::max(balance[0], -prices[1]);
 maxProfit[1] = std::max(0, prices[1] - prices[0]);

 for (int i = 2; i < len; ++i) {
 // balance[i-1]: do not purchase on day i
 // maxProfit[i-2] - prices[i]: purchase on day i
 balance[i] = std::max(balance[i-1], maxProfit[i-2] - prices[i]);

 // maxProfit[i-1]: do not sell on day i
 // balance[i-1] + prices[i]: sell on day i
 maxProfit[i] = std::max(maxProfit[i-1], balance[i-1] + prices[i]);
 }

 return maxProfit[len - 1];
 }
};

```

### Java solution

```
class Solution {
 public int maxProfit(int[] prices) {
 final int len = prices.length;
 if (len <= 1) {
 return 0;
 }
 else if (len == 2) {
 return Integer.max(0, prices[1] - prices[0]);
 }

 // len >= 3
 int[] balance = new int[len], maxProfit = new int[len];
 Arrays.fill(balance, Integer.MIN\_VALUE);

 balance[0] = -prices[0];

 balance[1] = Integer.max(balance[0], -prices[1]);
 maxProfit[1] = Integer.max(0, prices[1] - prices[0]);

 for (int i = 2; i < len; ++i) {
 // balance[i-1]: do not purchase on day i
 // maxProfit[i-2] - prices[i]: purchase on day i
 balance[i] = Integer.max(balance[i-1], maxProfit[i-2] - prices[i]);

 // maxProfit[i-1]: do not sell on day i
 // balance[i-1] + prices[i]: sell on day i
 maxProfit[i] = Integer.max(maxProfit[i-1], balance[i-1] + prices[i]);
 }

 return maxProfit[len - 1];
 }
}

```

## See also

* Best Time to Buy and Sell Stock II

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