---
# System prepended metadata

title: 123_Best_Time_to_Buy_and_Sell_Stock_III
tags: [leetcode]

---

# 123_Best_Time_to_Buy_and_Sell_Stock_III
###### tags: `leetcode`
## Problem Statement
Say you have an array for which the ith element is the price of a given stock on day i.

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

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

 

- Example 1:

> Input: prices = [3,3,5,0,0,3,1,4]
> Output: 6
> Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.

- Example 2:

> Input: prices = [1,2,3,4,5]
> Output: 4
> Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
> Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again.
- Example 3:

> Input: prices = [7,6,4,3,1]
> Output: 0
> Explanation: In this case, no transaction is done, i.e. max profit = 0.
- Example 4:

> Input: prices = [1]
> Output: 0
 
- Constraints:

> 1 <= prices.length <= 10^5^
> 0 <= prices[i] <= 10^5^

## Solution
- There is one more chance for transaction, after the normal procedure of looking for 1 transaction, there are 4 possibilities for adding 1 more transaction.
    1. Add 1 before the current one.
    2. Add 1 adter the current one.
    3. Split the current one into 2 transactions.
    4. Remain the same.
- As the result, when selecting the first transaction, store the begin and the end of the index.
```cpp=
// max_: the count of the gain
// temp: the lower bound candidate
// c: control of whether to write new lower bound
// change the lower and upper bound index when max_ is changed
for (int i= 1; i< prices.size(); i++)
{
    if (l+ prices[i]- prices[i- 1]> 0)
    {
        l+= prices[i]- prices[i- 1];
        if (c)
        {
            temp= i;
            c= 0;
        }
    }
    else
    {
        l= 0;
        c= 1;
    }
    if (max_< l)
    {
        max_= l;
        p2= i+ 1;
        p1= temp;
    }
}
```
- To compare whether adding one more transaction, the prerequisite is that there is transaction and the number of index need to be bigger than 1
```cpp=
if (p2!= 0&& prices.size()> 1)
```
- The 3 possibilities is considered:
1. Add one before transaction: count one transaction from the beginning till the lower bound.
```cpp=
for (int i= 1; i< p1; i++)
{
    l= max(l+ prices[i]- prices[i- 1], 0);
    max_l= max(max_l, l);
}
```
2. Add one after transaction: count one transaction from the upper bound till the end.
```cpp=
for (int i= p2; i< prices.size(); i++)
{
    l= max(l+ prices[i]- prices[i- 1], 0);
    max_r= max(max_r, l);
}
```
3. Split can be seperated into 2 cases:
    - Split from the smallest one among the middle
    - Split from the biggest one among the middle
Since the ```min_element()``` and ```max_element()``` gives the first smallest element without scanning all the index of the smallest element, the ```while``` loop is required. 
```cpp=
vector<int>::iterator a, b;
b= min_element(prices.begin()+ p1, prices.begin()+ p2- 1);
do
{
    a= max_element(prices.begin()+ p1, b);
    temp= (*a> *b)? prices[p2- 1]- *b+ *a- prices[p1- 1]: 0; 
    max_m= max(max_m, temp);
    b= find(b+ 1, prices.begin()+ p2- 1, *b);
}while (b!= prices.begin()+ p2- 1);
```
```cpp=
b= max_element(prices.begin()+ p1, prices.begin()+ p2- 1);
do
{
    a= min_element(b, prices.begin()+ p2- 1);
    temp= (*a< *b)? prices[p2- 1]- *a+ *b- prices[p1- 1]: 0; 
    max_m= max(max_m, temp);
    b= find(b+ 1, prices.begin()+ p2- 1, *b);
}while (b!= prices.begin()+ p2- 1);
```
- After all the possibilities, compare the result.
```cpp=
max_l= max(max_l, max_r);
max_= max(max_, max_+ max_l);
return max(max_, max_m);
```