← Static tasks

188. Best Time to Buy and Sell Stock IV

leetcode hard

#array#csharp#dynamic-programming#hard#leetcode#math

Task

Дан массив целых чисел prices, где prices[i] - это цена данной акции в i-й день, и целое число k.

Найдите максимальную прибыль, которую вы можете получить. Вы можете завершить не более чем k транзакций, т.е. вы можете купить не более k раз и продать не более k раз.

Обратите внимание: Вы не можете участвовать в нескольких транзакциях одновременно (т.е., вы должны продать акцию, прежде чем снова купить).

Пример:

Input: k = 2, prices = [2,4,1]

Output: 2

Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.

C# solution

matched/original
public class Solution {
    public int MaxProfit(int k, int[] prices) {
        int n = prices.Length;
        if (n == 0 || k == 0) return 0;
        if (k * 2 >= n) {
            int res = 0;
            for (int i = 1; i < n; i++)
                res += Math.Max(0, prices[i] - prices[i - 1]);
            return res;
        }
        var dp = new int[n, k + 1, 2];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= k; j++) {
                dp[i, j, 0] = Int32.MinValue / 2;
                dp[i, j, 1] = Int32.MinValue / 2;
            }
        }
        dp[0, 0, 0] = 0;
        dp[0, 1, 1] = -prices[0];
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= k; j++) {
                dp[i, j, 0] = Math.Max(dp[i - 1, j, 0], dp[i - 1, j, 1] + prices[i]);
                if (j > 0)
                    dp[i, j, 1] = Math.Max(dp[i - 1, j, 1], dp[i - 1, j - 1, 0] - prices[i]);
            }
        }
        int res = 0;
        for (int j = 0; j <= k; j++)
            res = Math.Max(res, dp[n - 1, j, 0]);
        return res;
    }
}

C++ solution

auto-draft, review before submit
#include <bits/stdc++.h>
using namespace std;

// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
class Solution {
public:
    public int MaxProfit(int k, vector<int>& prices) {
        int n = prices.size();
        if (n == 0 || k == 0) return 0;
        if (k * 2 >= n) {
            int res = 0;
            for (int i = 1; i < n; i++)
                res += max(0, prices[i] - prices[i - 1]);
            return res;
        }
        var dp = new int[n, k + 1, 2];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= k; j++) {
                dp[i, j, 0] = Int32.MinValue / 2;
                dp[i, j, 1] = Int32.MinValue / 2;
            }
        }
        dp[0, 0, 0] = 0;
        dp[0, 1, 1] = -prices[0];
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= k; j++) {
                dp[i, j, 0] = max(dp[i - 1, j, 0], dp[i - 1, j, 1] + prices[i]);
                if (j > 0)
                    dp[i, j, 1] = max(dp[i - 1, j, 1], dp[i - 1, j - 1, 0] - prices[i]);
            }
        }
        int res = 0;
        for (int j = 0; j <= k; j++)
            res = max(res, dp[n - 1, j, 0]);
        return res;
    }
}

Java solution

matched/original
public class Solution {
    public int maxProfit(int k, int[] prices) {
        int n = prices.length;

        if (n <= 0 || k <= 0) {
            return 0;
        }

        if (k * 2 >= n) {
            int res = 0;
            for (int i = 1; i < n; i++) {
                res += Math.max(0, prices[i] - prices[i - 1]);
            }
            return res;
        }
        int[][][] dp = new int[n][k + 1][2];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= k; j++) {
                dp[i][j][0] = -1000000000;
                dp[i][j][1] = -1000000000;
            }
        }
        dp[0][0][0] = 0;
        dp[0][1][1] = -prices[0];

        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= k; j++) {                dp[i][j][0] = Math.max(
                    dp[i - 1][j][0],
                    dp[i - 1][j][1] + prices[i]
                );
                if (j > 0) {
                    dp[i][j][1] = Math.max(
                        dp[i - 1][j][1],
                        dp[i - 1][j - 1][0] - prices[i]
                    );
                }
            }
        }

        int res = 0;
        for (int j = 0; j <= k; j++) {
            res = Math.max(res, dp[n - 1][j][0]);
        }

        return res;
    }
}

JavaScript solution

matched/original
class Solution {
    maxProfit(k, prices) {
        const n = prices.length;
        if (n === 0 || k === 0) return 0;
        if (k * 2 >= n) {
            let res = 0;
            for (let i = 1; i < n; i++) {
                res += Math.max(0, prices[i] - prices[i - 1]);
            }
            return res;
        }
        const dp = Array.from({ length: n }, () =>
            Array.from({ length: k + 1 }, () => Array(2).fill(Number.MIN_SAFE_INTEGER / 2))
        );
        dp[0][0][0] = 0;
        dp[0][1][1] = -prices[0];

        for (let i = 1; i < n; i++) {
            for (let j = 0; j <= k; j++) {
                dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
                if (j > 0) {
                    dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
                }
            }
        }
        return Math.max(...dp[n - 1].map(x => x[0]));
    }
}

Python solution

matched/original
class Solution:
    def maxProfit(self, k: int, prices: List[int]) -> int:
        n = len(prices)        if not prices or k == 0:
            return 0

        if k * 2 >= n:
            res = 0
            for i, j in zip(prices[1:], prices[:-1]):
                res += max(0, i - j)
            return res][ishold] = balance
        dp = [[[-math.inf] * 2 for _ in range(k + 1)] for _ in range(n)]
        dp[0][0][0] = 0
        dp[0][1][1] = -prices[0]
        for i in range(1, n):
            for j in range(k + 1):
                dp[i][j][0] = max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]
                if j > 0:
                    dp[i][j][1] = max(
                        dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]
                    )

        res = max(dp[n - 1][j][0] for j in range(k + 1))
        return res

Go solution

matched/original
type Solution struct{}

func maxProfit(k int, prices []int) int {
    n := len(prices)
    if n == 0 || k == 0 {
        return 0
    }
    if k*2 >= n {
        res := 0
        for i := 1; i < n; i++ {
            if prices[i] > prices[i-1] {
                res += prices[i] - prices[i-1]
            }
        }
        return res
    }
    dp := make([][][]int, n)
    for i := range dp {
        dp[i] = make([][]int, k+1)
        for j := range dp[i] {
            dp[i][j] = make([]int, 2)
            dp[i][j][0], dp[i][j][1] = -1<<31/2, -1<<31/2
        }
    }
    dp[0][0][0] = 0
    dp[0][1][1] = -prices[0]

    for i := 1; i < n; i++ {
        for j := 0; j <= k; j++ {
            dp[i][j][0] = max(dp[i-1][j][0], dp[i-1][j][1]+prices[i])
            if j > 0 {
                dp[i][j][1] = max(dp[i-1][j][1], dp[i-1][j-1][0]-prices[i])
            }
        }
    }
    res := 0
    for j := 0; j <= k; j++ {
        res = max(res, dp[n-1][j][0])
    }
    return res
}

func max(x, y int) int {
    if x > y {
        return x
    }
    return y
}

Explanation

Algorithm

1️⃣

Инициализация DP массива: Инициализируйте трехмерный массив dp, где dp[i][j][l] представляет максимальную прибыль на конец i-го дня с j оставшимися транзакциями и l акциями в портфеле. Начните с dp[0][0][0] = 0 (нет прибыли без акций и транзакций) и dp[0][1][1] = -prices[0] (покупка первой акции).

2️⃣

Вычисление переходов: Для каждого дня и каждого возможного количества транзакций вычислите возможные действия: держать акцию, не держать акцию, купить акцию, если j > 0, или продать акцию. Обновляйте dp с использованием:

dp[i][j][1] = max(dp[i−1][j][1], dp[i−1][j−1][0] - prices[i]) (максимум между удержанием акции и покупкой новой).

dp[i][j][0] = max(dp[i−1][j][0], dp[i−1][j][1] + prices[i]) (максимум между неудержанием акции и продажей).

3️⃣

Расчет результатов: По завершении всех дней, возвращайте максимальное значение dp[n-1][j][0] для всех j от 0 до k, что представляет максимальную прибыль без удержания акций на последний день. Обработайте специальный случай, когда 𝑘×2≥𝑛, чтобы избежать лишних расчетов.

😎