🧠
Brute Force (Pure Recursion)
💡 This approach explores all possible buy/sell decisions recursively without caching, which helps understand the problem structure but is inefficient.
Intuition
At each day, decide whether to buy, sell, or do nothing based on current holding state, recursively exploring all possibilities.
Algorithm
- Define a recursive function with parameters: current day and holding state.
- If at last day, return 0 profit if not holding, else negative infinity (can't sell after last day).
- If holding, choose max between selling today (add price - fee) or skipping.
- If not holding, choose max between buying today (subtract price) or skipping.
- Return the maximum profit from these choices.
💡 The recursion is hard because it branches into two choices per day and state, leading to exponential calls.
Recurrence:f(i, holding) = max( f(i+1, holding), f(i+1, !holding) + (prices[i] - fee if selling) or -prices[i] if buying )
def maxProfit(prices, fee):
n = len(prices)
from functools import lru_cache
@lru_cache(None)
def dfs(i, holding):
if i == n:
return 0 if not holding else float('-inf')
do_nothing = dfs(i + 1, holding)
if holding:
sell = dfs(i + 1, False) + prices[i] - fee
return max(do_nothing, sell)
else:
buy = dfs(i + 1, True) - prices[i]
return max(do_nothing, buy)
return dfs(0, False)
# Driver code
if __name__ == '__main__':
prices = [1,3,2,8,4,9]
fee = 2
print(maxProfit(prices, fee)) # Output: 8
Line Notes
def maxProfit(prices, fee):Defines main function to solve problem
@lru_cache(None)Caches results to avoid recomputation, turning brute force into memoization
if i == n:Base case: no more days left
return 0 if not holding else float('-inf')If holding at end, invalid state, so return negative infinity
do_nothing = dfs(i + 1, holding)Option to skip action today
if holding:If currently holding stock, can sell or skip
sell = dfs(i + 1, False) + prices[i] - feeProfit if selling today, pay fee
buy = dfs(i + 1, True) - prices[i]Profit if buying today, subtract price
import java.util.*;
public class Solution {
private int[] prices;
private int fee;
private Integer[][] memo;
public int maxProfit(int[] prices, int fee) {
this.prices = prices;
this.fee = fee;
this.memo = new Integer[prices.length][2];
return dfs(0, 0);
}
private int dfs(int i, int holding) {
if (i == prices.length) {
return holding == 0 ? 0 : Integer.MIN_VALUE / 2;
}
if (memo[i][holding] != null) return memo[i][holding];
int doNothing = dfs(i + 1, holding);
int res;
if (holding == 1) {
int sell = dfs(i + 1, 0) + prices[i] - fee;
res = Math.max(doNothing, sell);
} else {
int buy = dfs(i + 1, 1) - prices[i];
res = Math.max(doNothing, buy);
}
memo[i][holding] = res;
return res;
}
public static void main(String[] args) {
Solution sol = new Solution();
int[] prices = {1,3,2,8,4,9};
int fee = 2;
System.out.println(sol.maxProfit(prices, fee)); // Output: 8
}
}
Line Notes
private Integer[][] memo;Memoization table to cache results for states
if (i == prices.length)Base case: no more days
return holding == 0 ? 0 : Integer.MIN_VALUE / 2;Invalid if holding at end, return very negative
if (memo[i][holding] != null) return memo[i][holding];Return cached result if available
int doNothing = dfs(i + 1, holding);Option to skip action
if (holding == 1)If holding, can sell or skip
int sell = dfs(i + 1, 0) + prices[i] - fee;Profit if selling today
int buy = dfs(i + 1, 1) - prices[i];Profit if buying today
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
class Solution {
vector<int> prices;
int fee;
vector<vector<int>> memo;
public:
int dfs(int i, int holding) {
if (i == prices.size())
return holding == 0 ? 0 : INT_MIN / 2;
if (memo[i][holding] != INT_MIN)
return memo[i][holding];
int doNothing = dfs(i + 1, holding);
int res;
if (holding == 1) {
int sell = dfs(i + 1, 0) + prices[i] - fee;
res = max(doNothing, sell);
} else {
int buy = dfs(i + 1, 1) - prices[i];
res = max(doNothing, buy);
}
memo[i][holding] = res;
return res;
}
int maxProfit(vector<int>& prices, int fee) {
this->prices = prices;
this->fee = fee;
memo.assign(prices.size(), vector<int>(2, INT_MIN));
return dfs(0, 0);
}
};
int main() {
Solution sol;
vector<int> prices = {1,3,2,8,4,9};
int fee = 2;
cout << sol.maxProfit(prices, fee) << endl; // Output: 8
return 0;
}
Line Notes
vector<vector<int>> memo;Memo table to store computed states
if (i == prices.size())Base case: no more days
return holding == 0 ? 0 : INT_MIN / 2;Invalid state if holding at end
if (memo[i][holding] != INT_MIN)Return cached result if computed
int doNothing = dfs(i + 1, holding);Option to skip action
if (holding == 1)If holding, can sell or skip
int sell = dfs(i + 1, 0) + prices[i] - fee;Profit if selling today
int buy = dfs(i + 1, 1) - prices[i];Profit if buying today
var maxProfit = function(prices, fee) {
const n = prices.length;
const memo = new Map();
function dfs(i, holding) {
if (i === n) return holding === 0 ? 0 : Number.NEGATIVE_INFINITY;
const key = i + ',' + holding;
if (memo.has(key)) return memo.get(key);
const doNothing = dfs(i + 1, holding);
let res;
if (holding === 1) {
const sell = dfs(i + 1, 0) + prices[i] - fee;
res = Math.max(doNothing, sell);
} else {
const buy = dfs(i + 1, 1) - prices[i];
res = Math.max(doNothing, buy);
}
memo.set(key, res);
return res;
}
return dfs(0, 0);
};
// Test
console.log(maxProfit([1,3,2,8,4,9], 2)); // Output: 8
Line Notes
const memo = new Map();Memoization cache to avoid recomputation
if (i === n) return holding === 0 ? 0 : Number.NEGATIVE_INFINITY;Base case: no more days, invalid if holding
const doNothing = dfs(i + 1, holding);Option to skip action
if (holding === 1)If holding, can sell or skip
const sell = dfs(i + 1, 0) + prices[i] - fee;Profit if selling today
const buy = dfs(i + 1, 1) - prices[i];Profit if buying today
memo.set(key, res);Cache computed result for current state
TimeO(n*2) = O(n)
SpaceO(n*2) = O(n) due to recursion stack and memo
Each day and holding state is computed once due to memoization, total 2*n states.
💡 For n=100,000, this means about 200,000 computations, which is efficient enough with memoization.
Interview Verdict: Accepted with memoization; pure recursion without memo would TLE
Shows the importance of caching to avoid exponential time; pure brute force is impractical.