LeetCode算法题——Burst Balloons

题目概述

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:
(1) You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.
(2) 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

Example: 
Given [3, 1, 5, 8] 
Return 167

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

分析

此题首先想到分治思想,即分割nums数组。假设对于nums数组[a1,a2,a3,a4,a5,a6,......,an],将其分割成两个子整体,分割点为k,则得到 N1 = [a1,a2,a3,....,a(k-1)], N2 = [a(k+1),a(k+2),.....,an]。这里分割点k的意义是踩破了第k个气球。这样就把整体分成了两部分,再分别在被分割的各个子区间中来求出最大硬币数。

在计算最大硬币数的时候,需要运用到动态规划的思想。具体见代码实现:

// 第i个气球和第j个气球之间的最大硬币数
int DP(int i, int j, const vector &nums, vector > &dp) { 
        if (dp[i][j] > 0) return dp[i][j];
        for (int k = i; k <= j; k++) { // 假设分割点为k
            int temp = DP(i, k - 1, nums, dp) + nums[i - 1] * nums[k] * nums[j + 1] + DP(k + 1, j, nums, dp); // 分割数组,前后分治,中间进行计算
            if (temp > dp[i][j]) dp[i][j] = temp;
        }
        return dp[i][j];
    }
    int maxCoins(vector& nums) {
        int n = nums.size();
        nums.insert(nums.begin(), 1);
        nums.insert(nums.end(), 1); // 在首尾预插入1
        vector > dp(n + 2, vector(n + 2, 0)); 
        return DP(1, n, nums, dp);
    }

当然,如果想要达到更快的运算速度,也可以不使用分治递归策略,直接归纳出DP的状态方程:

int maxCoins(vector& nums) {
        int n = nums.size();
        nums.insert(nums.begin(), 1);
        nums.insert(nums.end(), 1);
        vector > dp(n + 2, vector(n + 2, 0));
        
        for (int k = 1; k <= n; k++) {
            for (int i = 1; i <= n - k + 1; i++) {
                int j = i + k - 1;
                for (int x = i; x <= j; x++) {
                    int temp = dp[i][x - 1] + nums[i - 1] * nums[x] * nums[j + 1] + dp[x + 1][j];
                    if (dp[i][j] < temp) dp[i][j] = temp;
                }
            }
        }
        return dp[1][n];
    }

总结

分治算法能够简化问题的求解过程,不会被子问题不断困扰,比较好理解,但缺点是代码执行的时间和空间复杂度较高;当然也可以改进状态方程,直接使用动态规划法,便可以实现更为快速的解题,不过需要考虑到更为复杂的边界情况。

你可能感兴趣的:(LeetCode算法题——Burst Balloons)