[Swift]LeetCode1000. 合并石头的最低成本 | Minimum Cost to Merge Stones

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/10464869.html 
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

There are N piles of stones arranged in a row.  The i-th pile has stones[i] stones.

A move consists of merging exactly K consecutive piles into one pile, and the cost of this move is equal to the total number of stones in these K piles.

Find the minimum cost to merge all piles of stones into one pile.  If it is impossible, return -1.

Example 1:

Input: stones = [3,2,4,1], K = 2
Output: 20
Explanation: 
We start with [3, 2, 4, 1].
We merge [3, 2] for a cost of 5, and we are left with [5, 4, 1].
We merge [4, 1] for a cost of 5, and we are left with [5, 5].
We merge [5, 5] for a cost of 10, and we are left with [10].
The total cost was 20, and this is the minimum possible.

Example 2:

Input: stones = [3,2,4,1], K = 3
Output: -1
Explanation: After any merge operation, there are 2 piles left, and we can't merge anymore.  So the task is impossible.

Example 3:

Input: stones = [3,5,1,2,6], K = 3
Output: 25
Explanation: 
We start with [3, 5, 1, 2, 6].
We merge [5, 1, 2] for a cost of 8, and we are left with [3, 8, 6].
We merge [3, 8, 6] for a cost of 17, and we are left with [17].
The total cost was 25, and this is the minimum possible. 

Note:

  • 1 <= stones.length <= 30
  • 2 <= K <= 30
  • 1 <= stones[i] <= 100

有 N 堆石头排成一排,第 i 堆中有 stones[i] 块石头。

每次移动(move)需要将连续的 K 堆石头合并为一堆,而这个移动的成本为这 K 堆石头的总数。

找出把所有石头合并成一堆的最低成本。如果不可能,返回 -1 。 

示例 1:

输入:stones = [3,2,4,1], K = 2
输出:20
解释:
从 [3, 2, 4, 1] 开始。
合并 [3, 2],成本为 5,剩下 [5, 4, 1]。
合并 [4, 1],成本为 5,剩下 [5, 5]。
合并 [5, 5],成本为 10,剩下 [10]。
总成本 20,这是可能的最小值。

示例 2:

输入:stones = [3,2,4,1], K = 3
输出:-1
解释:任何合并操作后,都会剩下 2 堆,我们无法再进行合并。所以这项任务是不可能完成的。.

示例 3:

输入:stones = [3,5,1,2,6], K = 3
输出:25
解释:
从 [3, 5, 1, 2, 6] 开始。
合并 [5, 1, 2],成本为 8,剩下 [3, 8, 6]。
合并 [3, 8, 6],成本为 17,剩下 [17]。
总成本 25,这是可能的最小值。 

提示:

  • 1 <= stones.length <= 30
  • 2 <= K <= 30
  • 1 <= stones[i] <= 100

32ms
 1 class Solution {
 2     struct State: Hashable {
 3         var range: Range<Int>, pileCount: Int
 4     }
 5     
 6     func mergeStones(_ stones: [Int], _ K: Int) -> Int {
 7         guard (stones.count - 1) % (K - 1) == 0 else {
 8             return -1
 9         }
10         
11         let prefixSum: [Int] = stones.reduce(into: [0]) { $0.append($0.last! + $1) }
12         func sum(in range: Range<Int>) -> Int {
13             return prefixSum[range.upperBound] - prefixSum[range.lowerBound]
14         }
15         
16         var states: [State: Int] = [:]
17         func minCost(in range: Range<Int>, pileCount: Int) -> Int {
18             if let result = states[State(range: range, pileCount: pileCount)] {
19                 return result
20             }
21             guard range.count != pileCount else {
22                 return 0
23             }
24             guard pileCount != 1 else {
25                 return minCost(in: range, pileCount: K) + sum(in: range)
26             }
27             
28             var result = Int.max
29             for split in stride(from: range.lowerBound + 1, to: range.upperBound, by: K - 1) {
30                 let first = minCost(in: range.lowerBound..<split, pileCount: 1)
31                 let second = minCost(in: split..<range.upperBound, pileCount: pileCount - 1)
32                 
33                 result = min(result, first + second)
34             }
35             
36             states[State(range: range, pileCount: pileCount)] = result
37             return result
38         }
39         
40         return minCost(in: stones.indices, pileCount: 1)
41     }
42 }

44ms

 1 class Solution {
 2     private var cache = [[[Int?]]]()
 3     private var prefixSum = [Int]()
 4     private var K = 0
 5     func mergeStones(_ stones: [Int], _ K: Int) -> Int {
 6         guard stones.count != 1 else { return 0 }
 7         guard (stones.count - 1) % (K - 1) == 0 else { return -1 }
 8         guard stones.count >= K else { return -1 }
 9         
10         self.K = K
11         
12         for i in 0..<stones.count {
13             var iArr = [[Int?]]()
14             for j in 0..<stones.count {
15                 var jArr = [Int?]()
16                 for k in 0...K {
17                     if i == j || k == j - i + 1 {
18                         jArr.append(0)
19                     } else {
20                         jArr.append(nil)
21                     }
22                 }
23                 iArr.append(jArr)
24             }
25             cache.append(iArr)
26         }
27         
28         prefixSum = [0]
29         
30         for stone in stones {
31             prefixSum.append(prefixSum[prefixSum.count - 1] + stone)
32         }
33         
34         return dp(0, stones.count - 1, 1)
35     }
36     
37     private func dp(_ i: Int, _ j: Int, _ k: Int) -> Int {
38         if let val = cache[i][j][k] {
39             return val
40         }
41         
42         let result: Int
43         
44         if k == 1 {
45             result = dp(i, j, K) + prefixSum[j + 1] - prefixSum[i]
46         } else {
47             var minimum = 9999999999999
48             var t = i
49             while t < j {
50                 minimum = min(minimum, dp(i, t, 1) + dp(t + 1, j, k - 1))
51                 t += (K - 1)
52             }
53             result = minimum
54         }
55         
56         cache[i][j][k] = result
57         return result
58     }
59 }

Runtime: 380 ms

Memory Usage: 19.3 MB
 1 class Solution {
 2     func mergeStones(_ stones: [Int], _ K: Int) -> Int {
 3         var n:Int = stones.count
 4         var pre:[Int] = [Int](repeating:0,count:n + 1)
 5         for i in 1...n
 6         {
 7             pre[i] = pre[i - 1] + stones[i - 1]
 8         }
 9         var inf:Int = 1000000000
10         var dp:[[[Int]]] = [[[Int]]](repeating:[[Int]](repeating:[Int](repeating:inf,count:205),count:205),count:205)
11         for i in 1...n
12         {
13             dp[i][i][1] = 0
14         }
15         for len in 1...n
16         {
17             var i:Int = 1
18             while(i + len - 1 <= n)
19             {
20                 var j:Int = i + len - 1
21                 if len >= 2
22                 {
23                     for k in 2...len
24                     {
25                         var t:Int = i
26                         while(t + 1 <= j)
27                         {
28                             dp[i][j][k] = min(dp[i][j][k], dp[i][t][k - 1] + dp[t + 1][j][1])
29                             t += 1
30                         }
31                     }
32                 }                
33                 dp[i][j][1] = min(dp[i][j][1], dp[i][j][K] + pre[j] - pre[i - 1])                
34                 i += 1
35             }
36         }
37         if dp[1][n][1] >= inf
38         {
39             return -1
40         }
41         return dp[1][n][1]
42     }
43 }

 

转载于:https://www.cnblogs.com/strengthen/p/10464869.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值