题目:有 N 堆石头排成一排,第 i 堆中有 stones[i] 块石头。每次移动(move)需要将连续的 K 堆石头合并为一堆,而这个移动的成本为这 K 堆石头的总数。找出把所有石头合并成一堆的最低成本。如果不可能,返回 -1 。
来源:https://leetcode-cn.com/problems/minimum-cost-to-merge-stones/
法一:自己的错误代码
思路:类似戳气球
法二:别人的代码
思路:dp[i][j]表示把stones从i到j合并成一堆后的最小值,dp[i][j]有两种情况,如果i到j恰好能合并成一堆,则要加上从i到j求和的,如果不能合并成一堆,则只有dp[i][k] + dp[k+1][i+m-1] for k in range(i, i+m-1, K-1)),特别要注意k之所以是等差数列,是为了让dp[i][k]合并成一堆,比如4 ! 6 8 7 ! 5 5 6 ! 9 3 2 ! 1 9 3. 这个数组,K=4,需要合并4次即可把它合并为一堆,之所以这样分一是因为dp[0][12]分成两堆时,都可以以四个感叹号中的一个作为分界,这样就包含了所有的情况,做到了不遗漏。二是如果不用合成一堆和k-1堆来分的话,即dp方程中的k是从i+1开始的话,这样会出错,出现0,如dp[0][3] K=3 dp[0][1] + dp[2][3] 就是0了,会出错。
from typing import List class Solution: def mergeStones(self, stones: List[int], K: int) -> int: N = len(stones) # 如果最终无法合并为一堆,直接返回-1 if (N - 1) % (K - 1): return -1 # 用于记录前n项和 prefix = [0] * (N+1) for i in range(1,N+1): prefix[i] = stones[i-1] + prefix[i-1] dp = [[0] * N for _ in range(N)] # m控制列的起始值, for m in range(K, N+1): # i控制行的终止值 for i in range(N-m+1): # 这里是dp的核心,dp[i][j]表示把stones合并成一堆后的最小值, dp[i][i+m-1] = min(dp[i][k] + dp[k+1][i+m-1] for k in range(i, i+m-1, K-1)) + (prefix[i+m] - prefix[i] if (m-1)%(K-1) == 0 else 0) print(dp) return dp[0][N-1] if __name__ == '__main__': duixiang = Solution() # a = duixiang.mergeStones(stones = [1,2,7,8,9,10,16], K = 3) a = duixiang.mergeStones(stones = [3, 5, 1, 2, 6,5,4], K = 3) # a = duixiang.mergeStones(stones = [3, 2, 4, 1], K = 2) # a = duixiang.mergeStones(stones = [6,4,4,6], K = 2) print(a)
ttt