Two Pointer Problems (Part 2) - Sliding Window
Two pointers are used to scan in two directions during traversal, achieving the desired algorithmic goals.
We can use
1. Selling on day might yield a higher profit compared to the previous profit ( ).
2. The previous profit is higher, so we don't do anything.
For case 1, the state transition equation is
The challenge now is how to represent
We realize that calculating
Now, let’s use
int maxProfit(vector<int>& prices) {
const int MAX = 100100;
int dp[MAX][2];
dp[0][1] = -prices[0],dp[0][0] = 0;
for (int i = 1; i < prices.size(); i++)
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]),
dp[i][1] = max(-prices[i], dp[i - 1][1]);
return dp[prices.size()-1][0];
}
Due to space limitations, optimizing space complexity is left for the reader to contemplate.
The difference between this and problem 121 lies in the fact that multiple buying operations are allowed here. Consequently, the state transition equation changes accordingly.
Based on the state transition equation from problem 121, when we sell on day
int maxProfit(vector<int>& prices) {
const int MAX = 100100;
int dp[MAX][2];
dp[0][1] = -prices[0],dp[0][0] = 0;
for (int i = 1; i < prices.size(); i++)
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]),
dp[i][1] = max(dp[i - 1][0]-prices[i], dp[i - 1][1]);
return dp[prices.size()-1][0];
}
This problem introduces a fixed transaction fee when selling. If the profit from selling on day
int maxProfit(vector<int>& prices, int fee) {
const int MAX = 100100;
int dp[MAX][2];
dp[0][1] = -prices[0],dp[0][0] = 0;
for (int i = 1; i < prices.size(); i++)
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee),
dp[i][1] = max(dp[i - 1][0]-prices[i], dp[i - 1][1]);
return dp[prices.size()-1][0];
}
This problem introduces a cooldown period after selling, meaning we can’t buy on the next day after selling. This changes the buying state transition equation as it can only happen after a cooldown period. Thus, the state transition equations become:
int maxProfit(vector<int>& prices) {
const int MAX = 100100;
int dp[MAX][3];
dp[0][1] = -prices[0],dp[0][0] = 0;
for (int i = 1; i < prices.size();
i++)
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]),
dp[i][1] = max(dp[i - 1][2]-prices[i], dp[i - 1][1]), //
dp[i][2] = dp[i - 1][0];
return dp[prices.size()-1][0];
}
This problem extends the concept from problem 121 and 122 by introducing a limit on the number of transactions (
int maxProfit(vector<int>& prices) {
const int MAX = 100100;
int dp[MAX][2][2];
dp[0][1][1] = dp[0][1][0] = -prices[0];
for (int i = 1; i < prices.size(); i++){
dp[i][0][0] = max(dp[i - 1][0][0], dp[i - 1][1][0] + prices[i]),
dp[i][1][0] = max(-prices[i], dp[i - 1][1][0]);
dp[i][0][1] = max(dp[i - 1][0][1], dp[i - 1][1][1] + prices[i]),
dp[i][1][1] = max(dp[i - 1][0][0]-prices[i], dp[i - 1][1][1]);
}
return dp[prices.size()-1][0][1];
}
Although not elegant, this code effectively solves the problem.
When the problem extends to
int maxProfit(int k, vector<int>& prices) {
if(prices.empty()) return NULL;
const int MAX = 1100;
int dp[MAX][2][110]={0};
for(int j = 0; j <= k; j++) dp[0][1][j] = -prices[0];
for(int i = 1; i < prices.size(); i++)
for(int j = 1; j <= k ; j++)
dp[i][0][j] = max(dp[i-1][1][j] + prices[i], dp[i-1][0][j]),
dp[i][1][j] = max(dp[i-1][0][j-1] - prices[i], dp[i-1][1][j]);
return dp[prices.size()-1][0][k];
}
For stock problems, the three limiting factors are:
Let
Stock problems have a close relationship with the concept of dynamic programming. Understanding the different types of dynamic programming problems can significantly help in quickly identifying subproblems and formulating state transition equations.