Open In App

Stock Buy and Sell with Transaction Fee

Last Updated : 04 Nov, 2025
Comments
Improve
Suggest changes
3 Likes
Like
Report

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

[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 <iostream>
#include <vector>

using namespace std;
//Driver Code Ends


// recursive function to calculate the profit
int maxProfitRec(vector<int> &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<int> &arr, int k) {
    int n = arr.size();
    
    return maxProfitRec(arr, 0, 0, k);
}


//Driver Code Starts
int main() {
    vector<int> 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

Output
8

[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 <iostream>
#include <vector>

using namespace std;
//Driver Code Ends


// recursive function to calculate the profit
int maxProfitRec(vector<int> &arr, int ind, 
              int buy, int k, vector<vector<int>> &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<int> &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<int> 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

Output
8

[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 <iostream>
#include <vector>

using namespace std;
//Driver Code Ends


int maxProfit(vector<int> &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<int> 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

Output
8

[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 <iostream>
#include <vector>
#include <algorithm>

using namespace std;
//Driver Code Ends


int maxProfit(vector<int> &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<int> 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

Output
8

Explore