Leetcode刷题(24) DP Table斜着遍历, 且只用Table的上半三角的动态规划
博弈问题
参考labuladong的动态规划之博弈问题
class Solution(object):
def stoneGame(self, piles):
"""
:type piles: List[int]
:rtype: bool
"""
n = len(piles)
dp = [[[0, 0] for _ in range(n)] for i in range(n)]
for i in range(n):
dp[i][i][0] = piles[i]
for i in range(n-1):
for j in range(n-1, i, -1):
# i, j状态时候先手拿左边的石头
left = dp[i+1][j][1] + piles[i]
# i, j状态时候先手拿右边的石头
right = dp[i][j-1][1] + piles[j]
# 如果先手拿左边的石头导致的剩下阶段的石头多, 就选择左边的并转移状态
if left > right:
dp[i][j][0] = left
dp[i][j][1] = dp[i+1][j][0]
# 如果先手拿右边的石头导致的剩下阶段的石头多, 就选择左边的并转移状态
else:
dp[i][j][0] = right
dp[i][j][1] = dp[i][j-1][0]
return dp[0][n-1][0] - dp[0][n-1][1] > 0
参考labuladong的动态规划: 戳气球
暴力回溯穷举并全局搜索最大分数法
class Solution(object):
def __init__(self):
self.maxNnm = -float('Inf')
def maxCoins(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
def backtrack(numbers, score):
if len(numbers) == 0:
self.maxNnm = max(self.maxNnm, score)
n = len(numbers)
for i in range(n):
# 记录将要被戳破气球的数字
tmp = nums[i]
# 得到将要被戳破的气球相邻两边的气球
if i - 1 < 0:
nums_1 = 1
else:
nums_1 = nums[i-1]
if i + 1 >= n:
nums_2 = 1
else:
nums_2 = nums[i + 1]
# 戳破索引为i的气球
point = nums_1 * tmp * nums_2
score += point
numbers.pop(i)
backtrack(numbers, score)
# 将之前被戳破的气球放回原位
numbers.insert(i, tmp)
score -= point
backtrack(nums, 0)
return self.maxNnm
DP Table, 斜着遍历
class Solution(object):
def maxCoins(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
dp = [[0] * (n + 2) for _ in range(n + 2)]
# 在nums的两边加上1, 作为辅助
nums.insert(0, 1)
nums.append(1)
# 遍历状态
for i in range(n + 1, -1, -1):
for j in range(i + 1, n + 2):
# 遍历选择(戳爆(i, j)中的哪一个是这个开区间中最后一个被戳爆的
for k in range(i + 1, j):
# 注意这里是nums[i] * nums[k] * nums[j], 不是nums[k-1] * nums[k] * nums[k+1]
dp[i][j] = max(dp[i][j], dp[i][k] + nums[i] * nums[k] * nums[j] + dp[k][j])
return dp[0][n+1]