leetcode 312. Burst Balloons

来源:互联网 发布:淘宝上专柜代购的衣服 编辑:程序博客网 时间:2024/05/18 05:04

写在前面

本题在leetcode上被标记为hard,是一道典型的动态规划问题,本题的难点在于状态转移方程的建立(其实就是题意的思路转换)。

题目描述

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

解题思路

能够想到dp,但几乎是毫无思路的,因为无法得到正确的状态转移方程(自顶向下),如果我们删除了某个数,它必然影响到左右两侧的数,进行下次删除时,无法得到正确的转移关系。
我们换种思路,从问题结束的状态往前推,确定最后一个被删除的数,然后左右两侧就是相同的子问题了,递归即可解。

class Solution {public:    int maxCoins(vector<int>& nums) {        //递归        vector<int>iNums;        iNums.push_back(1);        iNums.insert(iNums.end(),nums.begin(),nums.end());        iNums.push_back(1);        int left = 0;        int right = iNums.size()-1;        vector<vector<int>> memo(iNums.size(),vector<int>(iNums.size(),0));        return maxVal(left,right,iNums,memo);    }    int maxVal(int left,int right,vector<int>&iNums,vector<vector<int>> &memo) {        if(left+1==right) return 0;        int ans = 0;        if(memo[left][right]>0) return memo[left][right];        for(int i = left+1;i<right;++i) {            ans = max(ans,iNums[left]*iNums[i]*iNums[right]+maxVal(left,i,iNums,memo)+maxVal(i,right,iNums,memo));        }        memo[left][right] = ans;        return ans;    }};

一些改进

这两天一直没有更新博客,原因之一就是这道题目,在写完本题的题解之后,我又思考了一下,能不能不用递归来求解这个问题?我们知道,很多时候是要求避免使用递归式的,而对于动态规划问题,我们通常认为有两种解法,一种是自上而下的利用递归,一种是自底向上的解法,一般来讲,对于复杂问题,递归的思路更简单直接,但是,很多时候写出题解并不意味着你理解了动态规划的过程。我认为本题就属于这种情况,对于上述AC解,我们尝试将它改成自底向上的解,这就回到几个简单问题,问题的初始条件是什么,迭代过程是什么,更新的过程怎么走,最终的解是什么。对于本题,初始条件和迭代过程在递归的解法里都有了答案,关键是更新的过程。我们仔细思考整个动态规划过程,发现迭代的根本是left和right之间的数的个数,也就是说,这个个数作为步长,完成整个流程的更新,我们根据这个思路,写出最后的非递归AC解。

class Solution {public:    int maxCoins(vector<int>& nums) {        vector<int>iNums;        iNums.push_back(1);        iNums.insert(iNums.end(),nums.begin(),nums.end());        iNums.push_back(1);        int n = iNums.size();        vector<vector<int>> memo(n,vector<int>(n));        for(int k = 2;k<n;++k) {            for(int left = 0;left<n-k;++left) {                int right = left+k;                for(int i = left+1;i<right;++i) {                    memo[left][right] = max(memo[left][right],memo[left][i]+iNums[left]*iNums[i]*iNums[right]+memo[i][right]);                }            }        }        return memo[0][n-1];    }};
0 0
原创粉丝点击