LeetCode 312. Burst Balloons

原题链接:https://leetcode.com/problems/burst-balloons/

这是一道比较复杂的动态规划问题,关键在于定义好独立的子问题。

原问题可以转化为求f(i, j)的最大值,当i == 0 && j == n时,就是我们要的答案。

把j逐次向后移动,依次求f(0, 1), f(0, 2)... f(0, n)的最大值。

求f(0, j)的最大值,可以转化为子问题:在0..j中找到元素k,当k是最后一个戳破时,f(1, k-1) + f(k+1, j) + num[0] * num[k] * num[j+1]值最大。

更进一步的思考:

1. 为什么最后一定是num[0] * num[k] * num[j+1]?如果是num[i]*num[k]*num[j+1]构成最大呢?其实这种情况已经被k = i-1这种case考虑过了:

2. 怎样找到max(f(1, k-1) + f(k+1, j) + num[0] * num[k] * num[j+1])?

我们可以令i = j-1..1,然后让k = j..i+1,找到使得f(i,j) = f(i+1, k-1) + f(k+1, j) + num[i] * num[k] * num[j + 1]  最大的k。因为i是从j-1向1移动的,所以每次可以利用前一轮计算的结果,也就是说f(i+1, k-1) 和 f(k+1, j)其实之前已经计算过。

因为每次j移动时,会对之前的乘积造成影响,所以需要重新计算一遍f(i, j)。

代码如下:

 1 class Solution {
 2 public:
 3     int maxCoins(vector<int>& nums) {
 4         if(nums.size() == 0){
 5             return 0;
 6         }
 7         if(nums.size() == 1){
 8             return nums[0];
 9         }
10         
11         int size = nums.size();
12         nums.push_back(1);
13         nums.insert(nums.begin(), 1);
14         vector<vector<int>> mem(size + 1, vector<int>(size + 1, 0));
15         mem[1][1] = nums[1]*nums[2];
16         mem[size][size] = nums[size-1]*nums[size];
17         for(int i = 2; i < size; i++){
18             mem[i][i] = nums[i-1]*nums[i]*nums[i+1];
19         }
20         for(int j = 2; j <= size; j++){
21             for(int i = j - 1; i >=1; i--){
22                 for(int k = j; k >= i; k--){
23                     int product = nums[k] * nums[i-1] * nums[j+1];
24                     int left = i < k ? mem[i][k-1]:0; 
25                     int right = j > k? mem[k+1][j]:0; 
26                     int sum = product + left + right;
27                     mem[i][j] = max(sum, mem[i][j]);
28                 }
29             }
30         }
31         
32         return mem[1][size];
33     }
34 };
原文地址:https://www.cnblogs.com/k330/p/LeetCode_312_Burst_Balloons.html