2218.Maximum Value of K Coins From Piles

https://leetcode.com/problems/maximum-value-of-k-coins-from-piles/

這題是稍微複雜一點的 dynamic programming 的問題。

定義 dp[i][j] 爲 「在前 i 堆裡面選 j 次中最多硬幣的數量」。

對於 dp[i][j]
若是我在第 i 堆選 0 次,那麼我得到的硬幣數量是 dp[i - 1][j]
若是我在第 i 堆選 1 次,那麼我得到的硬幣數量是 dp[i - 1][j - 1] + piles[i][0]
若是我在第 i 堆選 2 次,那麼我得到的硬幣數量是 dp[i - 1][j - 2] + piles[i][0] + piles[i][1]

若是我在第 i 堆選 k 次,那麼我得到的硬幣數量是 dp[i - 1][j - k] + piles[i][0] + piles[i][1] + ... + piles[i][k]

若是我在第 i 堆選 j 次,那麼我得到的硬幣數量是 dp[i - 1][0] + piles[i][0] + piles[i][1] + ... + piles[i][j]

但是這邊要注意 k <= min(piles[i].size(), j),因爲第 i 堆最多只能選 piles[i].size() 那麼多次。

也就是說 dp[i][j] = max(dp[i - 1][j - k] + (piles[i][k])) for k = 0 to min(piles[i].size(), j)

那接下來就直接跑過 i, j 然後把上面的關係式套進去就好了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
int maxValueOfCoins(vector<vector<int>>& piles, int K) {
    int n = piles.size();
    vector<vector<int>> dp(n + 1, vector<int> (K + 1, 0));
    for (int i = 1; i <= n; i++){
        int size = piles[i - 1].size(); // 第 i 堆對應的 index 是 i - 1
        int prefix = 0;
        for (int j = 1; j <= K; j++){
            int prefix = 0;
            dp[i][j] = dp[i - 1][j];
            for (int k = 1; k <= size && k <= j; k++){
                prefix += piles[i - 1][k - 1];
                dp[i][j] = max(dp[i][j], prefix + dp[i - 1][j - k]);
            }
        }
    }
    return dp[n][K];
}

一樣也可以寫成 top down 的做法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int maxValueOfCoins(vector<vector<int>>& piles, int K) {
    int n = piles.size();
    vector<vector<int>> memo(n + 1, vector<int> (K + 1, 0));
    return dp(memo, piles, n, K);
}

int dp(vector<vector<int>> &memo, vector<vector<int>>& piles, int i, int j){
    if (i == 0 || j == 0){
        return 0;
    }
    if (memo[i][j] > 0){
        return memo[i][j];
    }
    int best = dp(memo, piles, i - 1, j);
    int prefix = 0;
    int size = piles[i - 1].size();
    for (int k = 1; k <= j && k <= size; k++){
        prefix += piles[i - 1][k - 1];
        best = max(best, dp(memo, piles, i - 1, j - k) + prefix);
    }
    memo[i][j] = best;
    return best;
}

time complexity: O( K * m ) where m = sum(piles[i].size())
當計算 dp[i][j] 時,for loop 要跑 piles[i - 1].size() 次,所以計算 dp[1][j]dp[n][j] 要跑 sum(piles[i].size()) 次。而 j 要從 1 跑到 K,所以總共要跑 K * sum(piles[i].size()) 次。
space complextiy: O( n * K )