返回

4步轻松掌握1753. 移除石子的最大得分

前端

刷题,是程序员终身的事业,欢迎来到我的刷题故事。今天要和大家分享的,是力扣第 1753 号题:移除石子的最大得分。

嗨,大家好,我是挨打的阿木木,爱好算法的前端摸鱼老。刷题,是程序员终身的事业,欢迎来到我的刷题故事。今天要和大家分享的,是力扣第 1753 号题:移除石子的最大得分。

众所周知,leetcode 1753题经常会被用在面试中,属于经典算法题,因此了解这道题的解法对求职面试有很大帮助。我们今天的重点,除了分享这道题的解法外,还会介绍一些刷题中的小技巧,让你用更短的时间写出更优美的代码。

好了,废话不多说,我们直接进入正题。这道题的题目如下:

给你一个长度为 n 的数组 piles ,其中 piles[i] 是第 i 堆石子的数量。
同时给你一个整数 k ,你需要将数组中的石子移除 k 次。每次移除时,你可以从数组中的任意一堆石子里移除任意数量的石子。
计算并返回移除 k 次石子后,堆中剩余石子的最大得分。
其中,石子堆的得分定义为石子堆中石子数量的 平方 。

例如:

输入:piles = [2,4,5], k = 2
输出:16
解释:
- 第 1 次移除,从堆 1 中移除 2 块石子,现在 piles = [0,2,5]。
- 第 2 次移除,从堆 3 中移除 2 块石子,现在 piles = [0,0,3]。
石子堆的得分为 (0^2 + 0^2 + 3^2) = 9,这是移除 k 次石子后石子堆的最大得分。

这道题的本质是一个动态规划问题。动态规划是一种常见的算法范式,用于解决具有重叠子问题和最优子结构性质的问题。动态规划的思想是将问题分解成较小的子问题,然后从最小的子问题开始逐步求解,最后将子问题的解组合起来得到原问题的解。

对于这道题,我们可以定义一个状态 dp[i][k] ,其中 dp[i][k] 表示在从第 i 堆石子开始移除石子,并且已经移除 k 次石子的情况下,堆中剩余石子的最大得分。然后,我们可以使用以下递推关系来计算 dp[i][k] :

dp[i][k] = max(dp[i + 1][k], dp[i + 1][k - 1] + piles[i] ^ 2)

其中,dp[i + 1][k] 表示在从第 i + 1 堆石子开始移除石子,并且已经移除 k 次石子的情况下,堆中剩余石子的最大得分。dp[i + 1][k - 1] + piles[i] ^ 2 表示在从第 i + 1 堆石子开始移除石子,并且已经移除 k - 1 次石子的情况下,堆中剩余石子的最大得分,加上第 i 堆石子中所有石子的得分。

使用动态规划来求解这道题的代码如下:

def max_score(piles, k):
  n = len(piles)
  dp = [[0] * (k + 1) for _ in range(n + 1)]

  for i in range(n - 1, -1, -1):
    for j in range(k, 0, -1):
      dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - 1] + piles[i] ^ 2)

  return dp[0][k]


piles = [2, 4, 5]
k = 2
print(max_score(piles, k))  # 16

上面讲解的是这道题的解法,下面我来分享一些刷题的小技巧。

  1. 巧妙地利用数据结构来简化问题。

例如,在这道题中,我们可以使用一个堆来存储石子堆的大小。这样,我们就可以在每次移除石子时,快速地找到最大的石子堆,并将其中的石子移除。

  1. 善于利用动态规划来解决问题。

动态规划是一种常见的算法范式,用于解决具有重叠子问题和最优子结构性质的问题。动态规划的思想是将问题分解成较小的子问题,然后从最小的子问题开始逐步求解,最后将子问题的解组合起来得到原问题的解。

  1. 多写代码,多练习。

刷题的目的是提高自己的编程能力。因此,在刷题时,一定要多写代码,多练习。只有这样,才能真正掌握算法和数据结构,并提高自己的编程水平。

希望我的刷题故事对大家有所帮助。我们下期再见!