LintCode编程题:吹气球问题

有n个气球,编号为0到n-1,

每个气球都有一个分数,存在nums数组中。

每次吹气球i可以得到的分数为 nums[left] * nums[i] * nums[right],left和right分别表示i气球相邻的两个气球。

当i气球被吹爆后,其左右两气球即为相邻。

要求吹爆所有气球,得到最多的分数。

样例 :
    给出 [4, 1, 5, 10] 
    返回 270

    nums = [4, 1, 5, 10] burst 1, 得分 4 * 1 * 5 = 20 
    nums = [4, 5, 10] burst 5, 得分 4 * 5 * 10 = 200  
    nums = [4, 10] burst 4, 得分 1 * 4 * 10 = 40 
    nums = [10] burst 10, 得分 1 * 10 * 1 = 10     

   总共的分数为 20 + 200 + 40 + 10 = 270

这道题应该使用动态规划的方法求解

首先按照题意,我们可以先在nums数组两端各加一个1,方便计算。 


solution_space[i , j]表示吹爆第i个到第j个气球能获得的最多的分数。对于第i 到 第j个气球中,可以首先吹爆任意一个气球k(i<=k<=j),吹爆第k个气球时,能获得的分数=nums[k]* [此刻k的前一个数]* [此刻k的后一个数],但是由于并不知道之前k左边和右边的气球有没有被吹爆,所以不能确定此刻左右的数。

换一种思路,既然可以首先吹爆任意一个气球k,那么也可以选择最后吹爆任意一个气球k。此时,k的左右数字就确定了,分别是nums[i-1]和nums[j+1]。

那么获得的分数就是nums[i-1]* nums[k]* nums[j+1],这是吹爆k获得的分数,再加上吹爆k之前获得的最大分数solution_space[i , k-1]+solution_space[k+1 , j](即在k之前吹爆的:k左边第i个到第k-1个,k右边第k+1个到第j个)。综上,solution_space[i , j]=max(nums[i-1]* nums[k]* nums[j+1] + solution_space[i , k-1]+ solution_space[k+1 , j]),(对于所有的 k : i<=k<=j).

显然,求solution_space[i , j]时,需要solution_space[i , k-1] , solution_space[k+1 , j],即区间长度小于i到j的区间长度的solution_space。所以可以从区间长度为1开始求解。这个和算法导论上动态规划那一章的矩阵链乘法类似。

最后的结果为 solution_space[1 , n]。

class Solution(object):

    def maxCoins(self, nums):

        # n在此处为初始列表的长度,下面要对原列表首位各加上1,之后nums列表的长度会比n增加2
        n=len(nums)
        
        # 在nums列表尾部加1,方便运算
        nums.append(1)
        
        # 在nums列表首部增加1,同样是为了方便运算。
        # insert函数第一个参数是增加在列表的什么位置,第二个参数是要增加的数字
        nums.insert(0,1)
        
        # 这一步完成对这个问题解空间的一种初始化
        # solution_space[i][j]代表了刚才说的吹爆第i个气球到第j个气球能获得的最高分数
        solution_space=[[0 for x in range(n+2)] for y in range(n+2)]
        
        # 此处的length表示了动态规划从下向上递增的序列,
        # 从 如果只吹爆一个气球的最高分开始,到只吹爆两个得到的最高分...逐步增加
        for length in range(1,n+1):
            
            # i表示了解空间solution_space[i][j]这个矩阵中的横行
            # 随着length的值逐渐变大(解空间变大)i的循环次数会逐渐变少
            # 注意:因为解空间大小是按照两头加过1以后的长度来建立的第0行和第5行其实全部都是0
            # 因此只会计算解空间(大矩阵)中[1][1]到[4][4]右上半部分
            for i in range(1,(n+2)-length):
                
                # 同理,j表示了解空间solution_space[i][j]这个矩阵中的纵行
                j=i+length-1
                
                # 变量初始化,q存储了递推式每次算出来的临时结果
                q=0
                
                # k代表了最后一个被吹爆的气球的位置,来源于i和j之间
                for k in range(i,j+1):
                    
                    #此处为之前推导的递推式求解
                    q=nums[i-1]*nums[k]*nums[j+1]+solution_space[i][k-1]+solution_space[k+1][j]
                    
                    # 每轮循环循环的最大答案将会保留在解空间的矩阵中
                    if q>solution_space[i][j]:
                        solution_space[i][j]=q

        return solution_space[1][n]

以上内容引用了六种鱼的博客。点击这里看原答案










你可能感兴趣的:(LintCode编程题:吹气球问题)