Problem Statement
You are given an integer array prices
 where prices[i]
 is the price of a given stock on the ith
 day.
On each day, you may decide to buy and/or sell the stock. You can only hold at most one  share of the stock at any time. However, you can buy it then immediately sell it on the same day .
Find and return the maximum  profit you can achieve .
Example 1:
Input: prices = [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
Total profit is 4 + 3 = 7.
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.
Total profit is 4.
Example 3:
Input: prices = [7,6,4,3,1]
Output: 0
Explanation: There is no way to make a positive profit, so we never buy the stock to achieve the maximum profit of 0.
Constraints:
1 <= prices.length <= 3 * 10^4
0 <= prices[i] <= 10^4
Solution:
1. Recursion
class Solution {
public int maxProfit ( int [] prices ) {
return trade (prices, 0 , false , 0 );
}
public int trade ( int [] prices , int day , boolean hasStock , int profit ){
if (day == prices.length){
return profit;
}
//Choice 1: Do nothing
int doNothing = trade (prices, day + 1 , hasStock, profit);
//Choice 2: Buy the stock if not holding
int buy = 0 ;
if ( ! hasStock){
buy = trade (prices, day + 1 , true , profit - prices[day]);
}
//Choice 3: Sell the stock if holding
int sell = 0 ;
if (hasStock){
sell = trade (prices, day + 1 , false , profit + prices[day]);
}
return Math. max (doNothing, Math. max (buy, sell));
}
}
2. Recursion and Memoization:
class Solution {
public int maxProfit ( int [] prices ) {
int [][] dp = new int [prices.length][ 2 ];
for ( int i = 0 ; i < prices.length; i ++ ) {
Arrays. fill (dp[i], - 1 );
}
//hasStock = 0 : don't have stock
//hasStock = 1 : have stock
return trade (prices, 0 , 0 , dp);
}
public int trade ( int [] prices , int day , int hasStock , int [][] dp ){
if (day == prices.length){
return 0 ;
}
if (dp[day][hasStock] != - 1 ){
return dp[day][hasStock];
}
//Choice 1: Do nothing
int doNothing = trade (prices, day + 1 , hasStock, dp);
//Choice 2: Buy the stock if not holding
int buy = 0 ;
if (hasStock == 0 ){
buy = trade (prices, day + 1 , 1 , dp) - prices[day];
}
//Choice 3: Sell the stock if holding
int sell = 0 ;
if (hasStock == 1 ){
sell = trade (prices, day + 1 , 0 , dp) + prices[day];
}
return dp[day][hasStock] = Math. max (doNothing, Math. max (buy, sell));
}
}
3. Tabulation:
class Solution {
public int maxProfit ( int [] prices ) {
int n = prices.length;
// dp[i][0] represents the maximum profit at the end of day i without holding a stock
// dp[i][1] represents the maximum profit at the end of day i holding a stock
int [][] dp = new int [n][ 2 ];
// Base case: At the beginning (day 0), the maximum profit without holding a stock is 0
dp[ 0 ][ 0 ] = 0 ;
// Base case: At the beginning (day 0), the maximum profit holding a stock is -prices[0]
dp[ 0 ][ 1 ] = - prices[ 0 ];
// Iterate through days starting from day 1
for ( int i = 1 ; i < n; i ++ ) {
// If not holding a stock on day i, we can either do nothing (stay not holding) or buy a stock
dp[i][ 0 ] = Math. max (dp[i - 1 ][ 0 ], dp[i - 1 ][ 1 ] + prices[i]);
// If holding a stock on day i, we can either do nothing (stay holding) or sell the stock
dp[i][ 1 ] = Math. max (dp[i - 1 ][ 1 ], dp[i - 1 ][ 0 ] - prices[i]);
}
// The maximum profit at the end of the last day without holding a stock is the final answer
return dp[n - 1 ][ 0 ];
}
}
3. Tabulation with space optimization:
class Solution {
public int maxProfit ( int [] prices ) {
int n = prices.length;
// dp[i][0] represents the maximum profit at the end of day i without holding a stock
// dp[i][1] represents the maximum profit at the end of day i holding a stock
int [] prev = new int [ 2 ];
int [] curr = new int [ 2 ];
// Base case: At the beginning (day 0), the maximum profit without holding a stock is 0
prev[ 0 ] = 0 ;
// Base case: At the beginning (day 0), the maximum profit holding a stock is -prices[0]
prev[ 1 ] = - prices[ 0 ];
// Iterate through days starting from day 1
for ( int i = 1 ; i < n; i ++ ) {
// If not holding a stock on day i, we can either do nothing (stay not holding) or buy a stock
curr[ 0 ] = Math. max (prev[ 0 ], prev[ 1 ] + prices[i]);
// If holding a stock on day i, we can either do nothing (stay holding) or sell the stock
curr[ 1 ] = Math. max (prev[ 1 ], prev[ 0 ] - prices[i]);
prev = curr. clone ();
}
// The maximum profit at the end of the last day without holding a stock is the final answer
return prev[ 0 ];
}
}
4. Greedy
Account for only increasing sequences
class Solution {
public int maxProfit ( int [] prices ) {
int profitSoFar = 0 , buyDate = 0 , sellDate = 0 ;
for ( int day = 1 ; day < prices.length; day ++ ){
if (prices[day] >= prices[day - 1 ]){
sellDate ++ ;
} else {
profitSoFar += prices[sellDate] - prices[buyDate];
sellDate = day;
buyDate = day;
}
}
//This the loop is necessary to account for the last potential profitable
//trade that may not have been settled within the loop.
profitSoFar += prices[sellDate] - prices[buyDate];
return profitSoFar;
}
}