Stock Buy and Sell with Transaction Fee (original) (raw)
Given an array **arr[] denoting the cost of stock on each day and an integer **k representing a **transaction fee. Find the maximum total profit if we can buy and sell the stocks any number of times given that each transaction costs fee k.
**Note: We can only sell a stock which we have bought earlier and we cannot hold multiple stocks on any day.
**Examples:
**Input: arr[] = [6, 1, 7, 2, 8, 4], k = 2
**Output: 8
**Explanation:
Buy the stock on day 2 and sell it on day 3 => 7 – 1 -2 = 4
Buy the stock on day 4 and sell it on day 5 => 8 – 2 - 2 = 4
Maximum Profit = 4 + 4 = 8**Input: arr[] = [7, 1, 5, 3, 6, 4], k = 1
**Output: 5
**Explanation:
Buy the stock on day 2 and sell it on day 3 => 5 – 1 - 1 = 3
Buy the stock on day 4 and sell it on day 5 => 6 – 3 - 1 = 2
Maximum Profit = 3 + 2 = 5
Table of Content
- [Naive Approach] - Using Recursion - O(2^n) Time and O(1) Space
- [Better Approach 1] - Using Memoization - O(n) Time and O(n) Space
- [Better Approach 2] - Using Tabulation - O(n) Time and O(n) Space
- [Expected Approach] Space Optimized - O(n) Time and O(1) Space
[Naive Approach] - Using Recursion - O(2n) Time and O(1) Space
The idea is to recursively generate all possible buy and sell combinations and compute the maximum among them. To do so, create a counter buy, which is 0 if no stock has been purchased else it is 1. Start from the 0th index, and for each index i, there are two possibilities:
- **buy == 0: If no stock has been purchased, we can either skip the stock arr[i], or can purchase it by subtracting arr[i] from profit.
- **buy == 1: If a stock has been purchased, we can't buy more and need to sell it. We can either sell it in current rate by adding arr[i] to profit and subtracting k of transaction fee, or skip to the next stock.
The maximum of this is the result.
C++ `
//Driver Code Starts #include #include
using namespace std; //Driver Code Ends
// recursive function to calculate the profit int maxProfitRec(vector &arr, int ind, int buy, int k) {
int n = arr.size();
// Base case
if (ind == n)
return 0;
int profit;
// if buy is 0, new stock can
// be purchased.
if (buy == 0) {
profit = max(maxProfitRec(arr, ind + 1, 0, k),
maxProfitRec(arr, ind + 1, 1, k) - arr[ind]);
}
// else stock can be sold
if (buy == 1) {
profit = max(maxProfitRec(arr, ind + 1, 1, k),
arr[ind] - k + maxProfitRec(arr, ind + 1, 0, k));
}
return profit;}
int maxProfit(vector &arr, int k) { int n = arr.size();
return maxProfitRec(arr, 0, 0, k);}
//Driver Code Starts int main() { vector arr = {6, 1, 7, 2, 8, 4}; int k = 2; cout << maxProfit(arr, k); return 0; } //Driver Code Ends
Java
//Driver Code Starts class GFG { //Driver Code Ends
// Recursive function to calculate the profit
static int maxProfitRec(int[] arr,
int ind, int buy, int k) {
int n = arr.length;
// Base case
if (ind == n)
return 0;
int profit;
// if buy is 0, new stock can
// be purchased.
if (buy == 0) {
profit = Math.max(maxProfitRec(arr, ind + 1, 0, k),
maxProfitRec(arr, ind + 1, 1, k) - arr[ind]);
}
// else stock can be sold
else {
profit = Math.max(maxProfitRec(arr, ind + 1, 1, k),
arr[ind] - k + maxProfitRec(arr, ind + 1, 0, k));
}
return profit;
}
static int maxProfit(int[] arr, int k) {
int n = arr.length;
return maxProfitRec(arr, 0, 0, k);
}//Driver Code Starts public static void main(String[] args) { int[] arr = {6, 1, 7, 2, 8, 4}; int k = 2; System.out.println(maxProfit(arr, k)); } }
//Driver Code Ends
Python
Recursive function to calculate the profit
def maxProfitRec(arr, ind, buy, k): n = len(arr)
# Base case
if ind == n:
return 0
# if buy is 0, new stock can
# be purchased.
if buy == 0:
profit = max(maxProfitRec(arr, ind + 1, 0, k),
maxProfitRec(arr, ind + 1, 1, k) - arr[ind])
# else stock can be sold
else:
profit = max(maxProfitRec(arr, ind + 1, 1, k),
arr[ind] - k + maxProfitRec(arr, ind + 1, 0, k))
return profitdef maxProfit(arr, k): n = len(arr)
return maxProfitRec(arr, 0, 0, k)if name == "main": #Driver Code Starts arr = [6, 1, 7, 2, 8, 4] k = 2 print(maxProfit(arr, k))
#Driver Code Ends
C#
//Driver Code Starts using System;
class GFG { //Driver Code Ends
// Recursive function to calculate the profit
static int maxProfitRec(int[] arr, int ind, int buy, int k) {
int n = arr.Length;
// Base case
if (ind == n)
return 0;
int profit;
// If buy is 0, new stock can be purchased
if (buy == 0) {
profit = Math.Max(maxProfitRec(arr, ind + 1, 0, k),
maxProfitRec(arr, ind + 1, 1, k) - arr[ind]);
}
// Else stock can be sold
else {
profit = Math.Max(maxProfitRec(arr, ind + 1, 1, k),
arr[ind] - k + maxProfitRec(arr, ind + 1, 0, k));
}
return profit;
}
// Function to calculate maximum profit
static int maxProfit(int[] arr, int k) {
int n = arr.Length;
return maxProfitRec(arr, 0, 0, k);
}//Driver Code Starts static void Main() { int[] arr = {6, 1, 7, 2, 8, 4}; int k = 2; Console.WriteLine(maxProfit(arr, k)); } }
//Driver Code Ends
JavaScript
// Recursive function to calculate the profit function maxProfitRec(arr, ind, buy, k) { let n = arr.length;
// Base case
if (ind === n)
return 0;
let profit;
// if buy is 0, new stock can
// be purchased.
if (buy === 0) {
profit = Math.max(maxProfitRec(arr, ind + 1, 0, k),
maxProfitRec(arr, ind + 1, 1, k) - arr[ind]);
}
// else stock can be sold
else {
profit = Math.max(maxProfitRec(arr, ind + 1, 1, k),
arr[ind] - k + maxProfitRec(arr, ind + 1, 0, k));
}
return profit;}
function maxProfit(arr, k) { let n = arr.length;
return maxProfitRec(arr, 0, 0, k);}
// Driver code //Driver Code Starts const arr = [6, 1, 7, 2, 8, 4]; const k = 2; console.log(maxProfit(arr, k));
//Driver Code Ends
`
[Better Approach 1] - Using Memoization - O(n) Time and O(n) Space
The above approach can be optimized using memoization. The idea is to create a 2d array memo[][] of order n*2, where element memo[i][0] stores the maximum profit from day i to n-1 when no previous stock is pending and memo[i][1] stores maximum profit from day i to n-1 when there is previous stock remaining. For each recursive call, check if the sub-array is already computed, if so return the stored value else proceed as in above approach.
C++ `
//Driver Code Starts #include #include
using namespace std; //Driver Code Ends
// recursive function to calculate the profit int maxProfitRec(vector &arr, int ind, int buy, int k, vector<vector> &memo) {
int n = arr.size();
// Base case
if (ind == n)
return 0;
// Check if the result is already computed
if (memo[ind][buy] != -1)
return memo[ind][buy];
int profit;
// if buy is 0, new stock can
// be purchased.
if (buy == 0) {
profit = max(maxProfitRec(arr, ind + 1, 0, k, memo),
maxProfitRec(arr, ind + 1, 1, k, memo) - arr[ind]);
}
// else stock can be sold
if (buy == 1) {
profit = max(maxProfitRec(arr, ind + 1, 1, k, memo),
arr[ind] - k + maxProfitRec(arr, ind + 1, 0, k, memo));
}
return memo[ind][buy] = profit;}
int maxProfit(vector &arr, int k) { int n = arr.size();
vector<vector<int>> memo(n, vector<int>(2, -1));
return maxProfitRec(arr, 0, 0, k, memo);}
//Driver Code Starts int main() { vector arr = {6, 1, 7, 2, 8, 4}; int k = 2; cout << maxProfit(arr, k); return 0; } //Driver Code Ends
Java
//Driver Code Starts import java.util.Arrays;
class GFG { //Driver Code Ends
// Recursive function to calculate the profit
static int maxProfitRec(int[] arr, int ind,
int buy, int k, int[][] memo) {
int n = arr.length;
// Base case
if (ind == n)
return 0;
// Check if the result is already computed
if (memo[ind][buy] != -1)
return memo[ind][buy];
int profit;
// if buy is 0, new stock can
// be purchased.
if (buy == 0) {
profit =
Math.max(maxProfitRec(arr, ind + 1, 0, k, memo),
maxProfitRec(arr, ind + 1, 1, k, memo) - arr[ind]);
}
// else stock can be sold
else {
profit =
Math.max(maxProfitRec(arr, ind + 1, 1, k, memo),
arr[ind] - k + maxProfitRec(arr, ind + 1, 0, k, memo));
}
return memo[ind][buy] = profit;
}
static int maxProfit(int[] arr, int k) {
int n = arr.length;
int[][] memo = new int[n][2];
for (int[] row : memo) {
Arrays.fill(row, -1);
}
return maxProfitRec(arr, 0, 0, k, memo);
}//Driver Code Starts public static void main(String[] args) { int[] arr = {6, 1, 7, 2, 8, 4}; int k = 2; System.out.println(maxProfit(arr, k)); } }
//Driver Code Ends
Python
Recursive function to calculate the profit
def maxProfitRec(arr, ind, buy, k, memo): n = len(arr)
# Base case
if ind == n:
return 0
# Check if the result is already computed
if memo[ind][buy] != -1:
return memo[ind][buy]
# Calculate profit
if buy == 0:
profit = max(maxProfitRec(arr, ind + 1, 0, k, memo),
maxProfitRec(arr, ind + 1, 1, k, memo) - arr[ind])
else:
profit = max(maxProfitRec(arr, ind + 1, 1, k, memo),
arr[ind] - k + maxProfitRec(arr, ind + 1, 0, k, memo))
memo[ind][buy] = profit
return profitdef maxProfit(arr, k): n = len(arr) memo = [[-1 for _ in range(2)] for _ in range(n)]
return maxProfitRec(arr, 0, 0, k, memo)if name == "main": #Driver Code Starts arr = [6, 1, 7, 2, 8, 4] k = 2 print(maxProfit(arr, k))
#Driver Code Ends
C#
//Driver Code Starts using System;
class GFG { //Driver Code Ends
// recursive function to calculate the profit
static int maxProfitRec(int[] arr, int ind,
int buy, int k, int[,] memo) {
int n = arr.Length;
// Base case
if (ind == n)
return 0;
// Check if the result is already computed
if (memo[ind, buy] != -1)
return memo[ind, buy];
int profit;
// if buy is 0, new stock can
// be purchased.
if (buy == 0) {
profit = Math.Max(maxProfitRec(arr, ind + 1, 0, k, memo),
maxProfitRec(arr, ind + 1, 1, k, memo) - arr[ind]);
}
// else stock can be sold
else {
profit = Math.Max(maxProfitRec(arr, ind + 1, 1, k, memo),
arr[ind] - k + maxProfitRec(arr, ind + 1, 0, k, memo));
}
memo[ind, buy] = profit;
return profit;
}
static int maxProfit(int[] arr, int k) {
int n = arr.Length;
int[,] memo = new int[n, 2];
for (int i = 0; i < n; i++) {
memo[i, 0] = -1;
memo[i, 1] = -1;
}
return maxProfitRec(arr, 0, 0, k, memo);
}//Driver Code Starts public static void Main(string[] args) { int[] arr = {6, 1, 7, 2, 8, 4}; int k = 2; Console.WriteLine(maxProfit(arr, k)); } }
//Driver Code Ends
JavaScript
// recursive function to calculate the profit function maxProfitRec(arr, ind, buy, k, memo) { let n = arr.length;
// Base case
if (ind === n)
return 0;
// Check if the result is already computed
if (memo[ind][buy] !== -1)
return memo[ind][buy];
let profit;
// if buy is 0, new stock can
// be purchased.
if (buy === 0) {
profit = Math.max(maxProfitRec(arr, ind + 1, 0, k, memo),
maxProfitRec(arr, ind + 1, 1, k, memo) - arr[ind]);
}
// else stock can be sold
else {
profit = Math.max(maxProfitRec(arr, ind + 1, 1, k, memo),
arr[ind] - k + maxProfitRec(arr, ind + 1, 0, k, memo));
}
memo[ind][buy] = profit;
return profit;}
function maxProfit(arr, k) { let n = arr.length; let memo = Array.from({ length: n }, () => Array(2).fill(-1));
return maxProfitRec(arr, 0, 0, k, memo);}
// Driver Code //Driver Code Starts const arr = [6, 1, 7, 2, 8, 4]; const k = 2; console.log(maxProfit(arr, k));
//Driver Code Ends
`
[Better Approach 2] - Using Tabulation - O(n) Time and O(n) Space
The idea is to use tabulation (bottom-up DP) approach and build the solution iteratively.
We create a 2D array dp[n + 1][2], where:
- n is the number of days.
- Each dp[i][buy] represents the **maximum profit that can be earned starting from day i, given whether we are allowed to buy (buy = 0) or sell (buy = 1).
We fill this table in a **bottom-up manner, starting from the last day and moving backward.
For each day i:
- **If we can buy (buy == 0): We have two options — buy the stock and subtract its price from profit, or skip to the next day.
dp[i][0] = max(-arr[i] + dp[i + 1][1], dp[i + 1][0])- **If we can sell (buy == 1): We can either sell the stock (add price to profit and subtract transaction fee k) or skip to the next day.
dp[i][1] = max(arr[i] - k + dp[i + 1][0], dp[i + 1][1])The base case is when we reach beyond the last index — profit is 0.
Finally, dp[0][0] gives the maximum profit possible starting from day 0 with the ability to buy.
C++ `
//Driver Code Starts #include #include
using namespace std; //Driver Code Ends
int maxProfit(vector &arr, int k) { int n = arr.size();
vector<vector<int>> dp(n+1, vector<int>(2, 0));
for (int ind = n - 1; ind >= 0; ind--) {
for (int buy = 0; buy <= 1; buy++) {
int profit;
// We can buy the stock
if (buy == 0) {
profit = max(dp[ind + 1][0],
dp[ind + 1][1] - arr[ind]);
}
// We can sell the stock
if (buy == 1) {
profit = max(dp[ind + 1][1],
arr[ind] - k + dp[ind + 1][0]);
}
dp[ind][buy] = profit;
}
}
// Return the maximum profit for buying.
return dp[0][0]; }
//Driver Code Starts int main() { vector arr = {6, 1, 7, 2, 8, 4}; int k = 2; cout << maxProfit(arr, k); return 0; } //Driver Code Ends
Java
//Driver Code Starts class GFG {
//Driver Code Ends
static int maxProfit(int[] arr, int k) {
int n = arr.length;
int[][] dp = new int[n + 1][2];
for (int ind = n - 1; ind >= 0; ind--) {
for (int buy = 0; buy <= 1; buy++) {
int profit;
// We can buy the stock
if (buy == 0) {
profit = Math.max(dp[ind + 1][0],
dp[ind + 1][1] - arr[ind]);
}
// We can sell the stock
else {
profit = Math.max(dp[ind + 1][1],
arr[ind] - k + dp[ind + 1][0]);
}
dp[ind][buy] = profit;
}
}
// Return the maximum profit for buying.
return dp[0][0];
}//Driver Code Starts public static void main(String[] args) { int[] arr = {6, 1, 7, 2, 8, 4}; int k = 2; System.out.println(maxProfit(arr, k)); } }
//Driver Code Ends
Python
def maxProfit(arr, k): n = len(arr)
dp = [[0 for _ in range(2)] for _ in range(n + 1)]
for ind in range(n - 1, -1, -1):
for buy in range(2):
# We can buy the stock
if buy == 0:
profit = max(dp[ind + 1][0],
dp[ind + 1][1] - arr[ind])
# We can sell the stock
else:
profit = max(dp[ind + 1][1],
arr[ind] - k + dp[ind + 1][0])
dp[ind][buy] = profit
# Return the maximum profit for buying.
return dp[0][0]if name == "main": #Driver Code Starts arr = [6, 1, 7, 2, 8, 4] k = 2 print(maxProfit(arr, k))
#Driver Code Ends
C#
//Driver Code Starts using System;
class GFG { //Driver Code Ends
static int maxProfit(int[] arr, int k) {
int n = arr.Length;
int[,] dp = new int[n + 1, 2];
for (int ind = n - 1; ind >= 0; ind--) {
for (int buy = 0; buy <= 1; buy++) {
int profit;
// We can buy the stock
if (buy == 0) {
profit = Math.Max(dp[ind + 1, 0],
dp[ind + 1, 1] - arr[ind]);
}
// We can sell the stock
else {
profit = Math.Max(dp[ind + 1, 1],
arr[ind] - k + dp[ind + 1, 0]);
}
dp[ind, buy] = profit;
}
}
// Return the maximum profit for buying.
return dp[0, 0];
}//Driver Code Starts static void Main(string[] args) { int[] arr = {6, 1, 7, 2, 8, 4}; int k = 2; Console.WriteLine(maxProfit(arr, k)); } }
//Driver Code Ends
JavaScript
function maxProfit(arr, k) { const n = arr.length;
const dp = Array.from({ length: n + 1 }, () => [0, 0]);
for (let ind = n - 1; ind >= 0; ind--) {
for (let buy = 0; buy <= 1; buy++) {
let profit;
// We can buy the stock
if (buy === 0) {
profit = Math.max(dp[ind + 1][0],
dp[ind + 1][1] - arr[ind]);
}
// We can sell the stock
else {
profit = Math.max(dp[ind + 1][1],
arr[ind] - k + dp[ind + 1][0]);
}
dp[ind][buy] = profit;
}
}
// Return the maximum profit for buying.
return dp[0][0];}
// Driver Code //Driver Code Starts const arr = [6, 1, 7, 2, 8, 4]; const k = 2; console.log(maxProfit(arr, k));
//Driver Code Ends
`
[Expected Approach] Space Optimized - O(n) Time and O(1) Space
Instead of using a DP table, we observe that each day’s profit depends only on the next day’s states.
So, we keep two variables:
- **noStock – profit when not holding a stock
- **inHand – profit when holding a stock
For each day (starting from the end):
- To **buy, choose between skipping or buying today → newNoStock = max(noStock, inHand - arr[i])
- To **sell, choose between skipping or selling today (paying fee k) → newInHand = max(inHand, arr[i] - k + noStock)
Update both states for the next iteration. Finally, noStock holds the maximum achievable profit.
C++ `
//Driver Code Starts #include #include #include
using namespace std; //Driver Code Ends
int maxProfit(vector &arr, int k) { int n = arr.size();
int noStock = 0, inHand = 0;
for (int i = n - 1; i >= 0; i--) {
// Choose to buy or skip
int newNoStock = max(noStock, inHand - arr[i]);
// Choose to sell or skip
int newInHand = max(inHand, arr[i] - k + noStock);
// Update states
noStock = newNoStock;
inHand = newInHand;
}
return noStock;}
//Driver Code Starts int main() { vector arr = {6, 1, 7, 2, 8, 4}; int k = 2;
cout << maxProfit(arr, k);
return 0;}
//Driver Code Ends
Java
//Driver Code Starts import java.util.ArrayList; import java.util.Arrays;
class GFG { //Driver Code Ends
static int maxProfit(int[] arr, int k) {
int n = arr.length;
int noStock = 0, inHand = 0;
for (int i = n - 1; i >= 0; i--) {
// Choose to buy or skip
int newNoStock = Math.max(noStock, inHand - arr[i]);
// Choose to sell or skip
int newInHand = Math.max(inHand, arr[i] - k + noStock);
// Update states
noStock = newNoStock;
inHand = newInHand;
}
return noStock;
}//Driver Code Starts public static void main(String[] args) { int[] arr = {6, 1, 7, 2, 8, 4}; int k = 2;
System.out.println(maxProfit(arr, k));
}}
//Driver Code Ends
Python
def maxProfit(arr, k): n = len(arr)
noStock, inHand = 0, 0
for i in range(n - 1, -1, -1):
# Choose to buy or skip
newNoStock = max(noStock, inHand - arr[i])
# Choose to sell or skip
newInHand = max(inHand, arr[i] - k + noStock)
# Update states
noStock, inHand = newNoStock, newInHand
return noStockif name == 'main': #Driver Code Starts arr = [6, 1, 7, 2, 8, 4] k = 2 print(maxProfit(arr, k))
#Driver Code Ends
C#
//Driver Code Starts using System; using System.Collections.Generic;
class GFG { //Driver Code Ends
static int maxProfit(int[] arr, int k) {
int n = arr.Length;
int noStock = 0, inHand = 0;
for (int i = n - 1; i >= 0; i--) {
// Choose to buy or skip
int newNoStock = Math.Max(noStock, inHand - arr[i]);
// Choose to sell or skip
int newInHand = Math.Max(inHand, arr[i] - k + noStock);
// Update states
noStock = newNoStock;
inHand = newInHand;
}
return noStock;
}//Driver Code Starts static void Main() { int[] arr = {6, 1, 7, 2, 8, 4}; int k = 2;
Console.WriteLine(maxProfit(arr, k));
}} //Driver Code Ends
JavaScript
function maxProfit(arr, k) { const n = arr.length;
let noStock = 0, inHand = 0;
for (let i = n - 1; i >= 0; i--) {
// Choose to buy or skip
const newNoStock = Math.max(noStock, inHand - arr[i]);
// Choose to sell or skip
const newInHand = Math.max(inHand, arr[i] - k + noStock);
// Update states
noStock = newNoStock;
inHand = newInHand;
}
return noStock;}
// Driver Code //Driver Code Starts const arr = [6, 1, 7, 2, 8, 4]; const k = 2; console.log(maxProfit(arr, k));
//Driver Code Ends
`