Start learning free

LESSON 346 OF 410 · DYNAMIC PROGRAMMING

Best Time to Buy and Sell Stock II - JavaScript Solution with Time Complexity Analysis

Practice O(n2) Read the full explanation

Say you have an array prices for which the i-th element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete at most k transactions.

Note:
You may not engage in multiple transactions at the same time (i.e. you must sell the stock before you buy again).

Example 1:

Input: prices = [2,4,1], k = 2
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.

Example 2:

Input: prices = [3,2,6,5,0,3], k = 2
Output: 7
Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4.
             Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
STEP 1 OF 8
    Ctrl + Enter to check

    JAVASCRIPT · DYNAMIC PROGRAMMING

    Best Time To Buy Stock in JavaScript, explained

    Understanding the Problem

    The core challenge of this problem is to maximize the profit from stock transactions given a constraint on the number of transactions. This problem is significant in financial applications where maximizing returns on investments is crucial. A common pitfall is to assume that buying and selling on every profitable day is optimal, which is not always the case due to the transaction limit.

    Approach

    To solve this problem, we need to consider both a naive and an optimized approach:

    Naive Approach

    The naive approach involves trying all possible pairs of buy and sell days, which is computationally expensive and not feasible for large inputs. This approach has a time complexity of O(n^2), where n is the number of days.

    Optimized Approach

    We can use dynamic programming to optimize the solution. The idea is to maintain a table where each entry represents the maximum profit achievable with a given number of transactions up to a certain day. This approach has a time complexity of O(n*k), where n is the number of days and k is the number of transactions.

    Algorithm

    Here is a step-by-step breakdown of the optimized algorithm:

    1. Initialize a 2D array `dp` where `dp[i][j]` represents the maximum profit up to day `i` with at most `j` transactions.
    2. Iterate over the number of transactions from 1 to k.
    3. For each transaction, iterate over the days and calculate the maximum profit by considering whether to sell on that day or not.
    4. Update the `dp` table accordingly.

    Code Implementation

    /**
     * @param {number[]} prices
     * @param {number} k
     * @return {number}
     */
    function maxProfit(k, prices) {
        const n = prices.length;
        if (n === 0) return 0;
    
        // If k is greater than n/2, it's equivalent to unlimited transactions
        if (k >= n / 2) {
            let maxProfit = 0;
            for (let i = 1; i < n; i++) {
                if (prices[i] > prices[i - 1]) {
                    maxProfit += prices[i] - prices[i - 1];
                }
            }
            return maxProfit;
        }
    
        const dp = Array.from({ length: k + 1 }, () => Array(n).fill(0));
    
        for (let t = 1; t <= k; t++) {
            let maxDiff = -prices[0];
            for (let d = 1; d < n; d++) {
                dp[t][d] = Math.max(dp[t][d - 1], prices[d] + maxDiff);
                maxDiff = Math.max(maxDiff, dp[t - 1][d] - prices[d]);
            }
        }
    
        return dp[k][n - 1];
    }
    

    Complexity Analysis

    The time complexity of the optimized approach is O(n*k), where n is the number of days and k is the number of transactions. The space complexity is also O(n*k) due to the 2D array used for dynamic programming.

    Edge Cases

    Potential edge cases include:

    • Empty prices array: The function should return 0.
    • k greater than or equal to half the number of days: This can be treated as unlimited transactions.

    Testing

    To test the solution comprehensively, consider the following test cases:

    • Simple cases with small arrays.
    • Cases with no profitable transactions.
    • Cases with multiple profitable transactions.

    Thinking and Problem-Solving Tips

    When approaching such problems, it's essential to:

    • Understand the constraints and edge cases.
    • Start with a naive solution and then optimize.
    • Use dynamic programming for problems involving optimal substructure and overlapping subproblems.

    Conclusion

    Understanding and solving the "Best Time to Buy and Sell Stock II" problem helps in developing skills in dynamic programming and optimization. Practice is key to mastering such problems.

    Additional Resources

    For further reading and practice, consider the following resources:

    Keep going with JavaScriptAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free