LeetCode Everyday - 从栈中取出 K 个硬币的最大面值和

130 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情

从栈中取出 K 个硬币的最大面值和

一张桌子上总共有 n 个硬币 栈 。每个栈有 正整数 个带面值的硬币。

每一次操作中,你可以从任意一个栈的 顶部 取出 1 个硬币,从栈中移除它,并放入你的钱包里。

给你一个列表 piles ,其中 piles[i] 是一个整数数组,分别表示第 i 个栈里 从顶到底 的硬币面值。同时给你一个正整数 k ,请你返回在 恰好 进行 k 次操作的前提下,你钱包里硬币面值之和 最大为多少 。  

示例1:

image.png

输入:piles = [[1,100,3],[7,8,9]], k = 2
输出:101
解释:
上图展示了几种选择 k 个硬币的不同方法。
我们可以得到的最大面值为 101

示例2:

输入:piles = [[100],[100],[100],[100],[100],[100],[1,1,1,1,1,1,700]], k = 7
输出:706
解释:
如果我们所有硬币都从最后一个栈中取,可以得到最大面值和。

提示:

  • n == piles.length
  • 1 <= n <= 1000
  • 1 <= piles[i][j] <= 105
  • 1 <= k <= sum(piles[i].length) <= 2000

解题思路:

记忆化搜索 dfs(i, c) 表示从索引为 idx 的栈开始取,还可以取 c 次的最大和

我的答案:

/**
 * @param {number[][]} piles
 * @param {number} k
 * @return {number}
 */

var maxValueOfCoins = function(piles, k) {
  const m = piles.length;
  const preSum = new Array(m).fill(0).map(() => []);
  
  for (let i = 0; i < m; i++) {
    let sum = 0;
    preSum[i].push(0);
    for (let j = 0; j < piles[i].length; j++) {
      sum += piles[i][j];
      preSum[i].push(sum);
    }
  }
  
  const dfs = (i, c, memo) => {
    if (i >= m || c <= 0) {
      return 0;
    }
    
    if (memo[i][c] !== -1) {
      return memo[i][c];
    }
    
    let max = -Infinity;
    for (let j = 0; j <= Math.min(piles[i].length, c); j++) {
      max = Math.max(
        max,
        preSum[i][j] + dfs(i + 1, c - j, memo)
      );
    }
    
    memo[i][c] = max;
    return memo[i][c];
  }
  
  return dfs(0, k, new Array(m).fill(0).map(() => new Array(k + 1).fill(-1)));
};

最后

如果有更好的解法或者思路, 欢迎在评论区和我交流~ ღ( ´・ᴗ・` )