算法题:打气球的最大分数
最近在看左程云的《程序员代码面试指南》,感觉不错,题都分了类,很方便有目的的刷题,书里的代码都是java实现的,刚好最近在学习python,就用python去练习一下。
1. 问题描述
给定一个数组arr,代表一排有分数的气球。 每打爆一个气球都能获得分数,假设打爆气球的分数为X,获得分数的规则如下:
1)如果被打爆气球的左边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为L:如果被打爆气球的右边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为R.获得分数为LXR
2)如果被打爆的气球的左边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为L:如果被打爆气球的右边所有气球都已经被打爆,获得分数为LX。
3)如果被打爆气球的左边所有的气球都已经被打爆:如果被打爆气球的右边有没被打爆的气球,找到离被打爆气球最近的气球。获得分数为XR.
4)如果被打爆气球的左边和右边所有的气球都已经被打爆。获得分数为X。
目标是打爆所有气球,获得每次打爆的分数。通过选择打爆气球的顺序,可以得到不同的总分,请返回能获得的最大分数
2.解决方法
1)暴力递归:假设arr[L-1]和arr[R+1]都没爆,要打爆arr[L]到arr[R]的气球,假设arr为[L~R],可以设置一个help数组,添加arr[L-1]和arr[R+1]并将值值设为1。如此便对于相乘便无影响。对于L和R位置,对于普通位置i分别递归地求解。
2)动态规划:以L和R为可变参数作m表,将表画出可以发现,m[i][j]代表i~j上打爆所有气球的最大分数,对于每个位置,其值只依赖于其左侧和正下方的值。则从下往上的完成m表,可以得到结果。
3.代码实现
暴力递归
# 暴力递归
def process(arr, L, R):
if L == R:
return arr[L-1] * arr[L] * arr[R+1]
max_score = max(arr[L-1] * arr[L] * arr[R+1] + process(arr, L+1, R), arr[L-1] * arr[R] * arr[R+1] + process(arr, L, R-1))
for i in range(L+1, R):
max_score = max(max_score, arr[L-1] * arr[i] * arr[R+1] + process(arr, L, i-1) + process(arr, i+1, R))
return max_score
动态规划
# 动态规划
def score(arr):
m = [[0 for i in range(len(arr))] for j in range(len(arr))]
for i in range(1, len(arr)-1):
m[i][i] = arr[i-1] * arr[i] * arr[i+1]
# 求解m[i][j],m[i][j]代表i~j上打爆所有气球的最大分数
L = len(arr) - 2
while L >= 1:
R = L + 1
while R <= len(arr) - 2:
# 最后打爆arr[L]的情况
finalL = arr[L-1] * arr[L] * arr[R+1] + m[L+1][R]
# 最后打爆arr[R]的情况
finalR = arr[R+1] * arr[R] * arr[L-1] + m[L][R-1]
# 先比较一下arr[L]和arr[R]的情况
m[L][R] = max(finalL, finalR)
# 对一般情况进行分析
for i in range(L+1, R):
m[L][R] = max(m[L][R], arr[L-1] * arr[i] * arr[R+1] + m[L][i-1] + m[i+1][R])
R += 1
L -= 1
print("m表:")
for item in m:
for i in item:
print(i, end = '\t')
print()
return m[1][len(arr)-2]
if __name__ == "__main__":
help_arr = [1, 4, 2, 3, 5, 1, 6, 1]
print("(递归)最大分数为:{0}".format(process(help_arr, 1, 6)))
print("(动态规划)最大分数为:{0}".format(score(help_arr)))
结果:
(递归)最大分数为:264
m表:
0 0 0 0 0 0 0 0
0 8 36 104 109 258 264 0
0 0 24 84 104 234 258 0
0 0 0 30 40 156 168 0
0 0 0 0 15 120 138 0
0 0 0 0 0 30 60 0
0 0 0 0 0 0 6 0
0 0 0 0 0 0 0 0
(动态规划)最大分数为:264