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(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:

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 profit

def 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 profit

def 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:

We fill this table in a **bottom-up manner, starting from the last day and moving backward.

For each day i:

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:

For each day (starting from the end):

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 noStock

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; 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

`