1. 程式人生 > >【LeetCode】312. Burst Balloons 解題報告(Python)

【LeetCode】312. Burst Balloons 解題報告(Python)

題目描述:

Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by array nums. You are asked to burst all the balloons. If the you burst balloon i you will get nums[left] * nums[i] * nums[right] coins. Here left and right are adjacent indices of i. After the burst, the left

and right then becomes adjacent.

Find the maximum coins you can collect by bursting the balloons wisely.

Note:

  • You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.
  • 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

Example:

Input: [3,1,5,8]
Output: 167 
Explanation: nums = [3,1,5,8] --> [3,5,8] -->   [3,8]   -->  [8]  --> []
             coins =  3*1*5      +  3*5*8    +  1*3*8      + 1*8*1   = 167

題目大意

打氣球遊戲,當我們打某個位置的氣球的時候,能獲得它左右兩個氣球上的分數和自身分數的乘積。問如何打氣球能獲得最多的分數?可以認為最左右兩邊隱含著分數為1不用打破的氣球。

解題方法

這個是個DP的題目,當然也可以通過記憶化搜尋的方式解決。

令dfs(i, j) 和 c[i][j]是在第[i, j]閉區間上打破氣球能獲得最大值。那麼,在其中找到一個不打破的氣球k,則可以得到以下關係:

c[i][j] = max(c[i][j], self.dfs(nums, c, i, k - 1) + nums[i - 1] * nums[k] * nums[j + 1] + self.dfs(nums, c, k + 1, j))

含義是,我們找出在[i, k - 1]、[k + 1, j]閉區間打氣球的分數最大值,然後會把第i - 1和第j + 1個氣球保留下來,讓這兩個氣球和第k個氣球相乘,最後求三個加法。

模擬左右兩邊的氣球的方法是直接新增上首尾各一個1,同時使用記憶化能加速不少,也為下一步的DP提供思路。

時間複雜度是O(N^2 * log(N))(不會算…),空間複雜度是O(N)。

class Solution(object):
    def maxCoins(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        nums.insert(0, 1)
        nums.append(1)
        c = [[0] * (n + 2) for _ in range(n + 2)]
        return self.dfs(nums, c, 1, n)
        
    def dfs(self, nums, c, i, j):
        if i > j: return 0
        if c[i][j] > 0: return c[i][j]
        if i == j: return nums[i - 1] * nums[i] * nums[i + 1]
        res = 0
        for k in range(i, j + 1):
            res = max(res, self.dfs(nums, c, i, k - 1) + nums[i - 1] * nums[k] * nums[j + 1] + self.dfs(nums, c, k + 1, j))
        c[i][j] = res
        return c[i][j]

第二種解法是使用DP。

DP一般都可以通過記憶化搜尋來改出來,但是我不會。。很遺憾,參考了別人的程式碼,還是沒搞懂。。

class Solution(object):
    def maxCoins(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        nums.insert(0, 1)
        nums.append(1)
        dp = [[0] * (n + 2) for _ in range(n + 2)]
        for len_ in range(1, n + 1):
            for left in range(1, n - len_ + 2):
                right = left + len_ - 1
                for k in range(left, right + 1):
                    dp[left][right] = max(dp[left][right], dp[left][k - 1] + nums[left - 1] * nums[k] * nums[right + 1] + dp[k + 1][right])
        return dp[1][n]

參考資料:

日期

2018 年 10 月 2 日 —— 小藍單車莫名其妙收了我1塊錢,明明每個月免費騎10次的啊!