Intuition 1¶
Approach 1¶
1.Initialization:¶
- The
dparray is initialized with-1to indicate states.
2.Dynamic Programming Table (3D DP array):¶
The solution uses a 3D DP array dp[i][canBuy][trans] where:
- i is the current day.
- canBuy indicates whether we can buy a stock on the current day (1 if we can buy, 0 if we can sell).
- trans is the number of transactions (buy + sell pairs) completed so far.
3.Base Cases:¶
- If
iis equal to the length of the prices array(i == n), we cannot make any transactions, so the profit is0. - If
transreachesk, we cannot make more thanktransactions, so the profit is0.
4.State Transition:¶
- If
canBuy == 1, we have two choices:- 1.Buy the stock at price
v[i]and move to the next day withcanBuyset to0(indicating the next action should be sell). - 2.Skip the current day without buying and move to the next day with
canBuystill set to1.
- 1.Buy the stock at price
- If
canBuy == 0, we also have two choices:- 1.Sell the stock at price
v[i]and move to the next day withcanBuyset to1(indicating the next action should be buy), and increment the trans by1. - 2.Skip the current day without selling and move to the next day with
canBuystill set to0.
- 1.Sell the stock at price
5.Memoization:¶
- The results of sub-problems are stored in the DP array to avoid redundant calculations.
6.Recursive Function:¶
- The recursive function
fcomputes the maximum profit for each state using the defined state transitions and memoization.
Complexity¶
-
Time complexity: O(N2*K)
-
Space complexity: O(N*K)
Code¶
class Solution {
public:
int dp[1005][2][105];
int f(int i,int canBuy,vector<int>&v,int trans,int k){
int n=v.size();
if(i==n||trans>=k)return 0;
if(dp[i][canBuy][trans]!=-1)return dp[i][canBuy][trans];
if(canBuy) dp[i][canBuy][trans]=max(-v[i]+f(i+1,0,v,trans,k),f(i+1,1,v,trans,k));
else dp[i][canBuy][trans]=max(v[i]+f(i+1,1,v,trans+1,k),f(i+1,0,v,trans,k));
return dp[i][canBuy][trans];
}
int maxProfit(int k, vector<int>& prices) {
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
memset(dp,-1,sizeof dp);
return f(0,1,prices,0,k);
}
};
Intuition 2¶
- If I use greedy thinking to buy all trades, how can I optimize them further to fit within k trades?
Approach 2¶
1.Initial Setup:¶
- The function takes the number of allowed transactions
kand a vector of stock pricesprices. - Initialize
nas the size of thepricesvector. - Initialize
btoINT_MAXto track the lowest buying price. - Initialize a vector of pairs
bsto store all potential buy-sell pairs.
2.Identify Buy-Sell Pairs:¶
Iterate through the prices array to identify all potential buy-sell pairs:
- If the current price is less than or equal to b, update b to the current price.
- If the current price is greater than b, iterate through consecutive days where the price is non-decreasing to find the peak price.
- Store the buy-sell pair (b, prices[i]) in the bs vector and update b to the current price.
3.Reduce Transactions:¶
If the number of identified buy-sell pairs exceeds k, reduce the number of transactions by either merging two consecutive trades or deleting a single trade:
- Merge Consecutive Trades: Find the pair of consecutive trades where merging them results in the minimum loss and merge these trades.
- Delete a Trade: Find the trade with the smallest profit and delete it.
- Continue reducing until the number of transactions is less than or equal to k.
4.Calculate Maximum Profit:¶
- Initialize
ansto store the total profit. - Sum up the profits of all remaining buy-sell pairs in the
bsvector. - Return the total profit as the result.
Complexity¶
-
Time complexity: O(N)
-
Space complexity: O(N)
Code¶
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
int b = INT_MAX;
vector<pair<int, int>> bs;
for(int i=0;i<n;i++){
if(prices[i]<=b) b = prices[i];
else{
while(i<n-1 && prices[i+1]>=prices[i]){
i++;
}
bs.push_back({b, prices[i]});
b = prices[i];
}
}
while(bs.size()>k){
int mergeIdx = -1, _min = INT_MAX;
for(int i=1;i<bs.size();i++){
if(bs[i].second >= bs[i-1].second && bs[i-1].second-bs[i].first < _min){
mergeIdx = i;
_min = bs[i-1].second-bs[i].first;
}
}
int minIdx = 0;
for(int i=1;i<bs.size();i++){
if((bs[i].second-bs[i].first)<(bs[minIdx].second-bs[minIdx].first)) minIdx = i;
}
if(bs[minIdx].second-bs[minIdx].first < _min) bs.erase(bs.begin()+minIdx);
else{
bs[mergeIdx-1].second = bs[mergeIdx].second;
bs.erase(bs.begin()+mergeIdx);
}
}
long int ans = 0;
for(auto p:bs)ans+=p.second-p.first;
return ans;
}
};