1000合并石头的最低成本

题目:有 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)
View Code

ttt

 

posted on 2020-02-02 22:39  吃我一枪  阅读(217)  评论(0编辑  收藏  举报

导航