dp考虑先后手的区别
def PredictTheWinner(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
#定义dp[i][j][0] 是1先手在[i,j]区间可以得到的最大分数
#定义dp[i][j][1] 是2后手在[i,j]区间可以得到的最大分数
#dp[i][i][0] = nums[i]
#先手选左边 dp[i][j][0] = dp[i+1][j][1] + nums[i] , 后手剩下 dp[i][j][1] = dp[i+1][j][0]
#先手选右边 dp[i][j][0] = dp[i][j-1][1] + nums[j] , 后手剩下 dp[i][j][1] = dp[i][j-1][0]
#解释上面的,先手选了左边,加上左边的元素,做完选择之后变成了后手所以是加上dp[i+1][j][1]选择后的后手
# 先手选了左边,后手此时变成了先手,还剩下先手选择完的piles[i+1...j]变成了dp[i+1][j][0]
n = len(nums)
dp = [[[0,0] for i in range(n)] for j in range(n)]
for i in range(n):
dp[i][i][0] = nums[i]
for i in range(n-2,-1,-1):
for j in range(i+1,n):
left = dp[i+1][j][1] + nums[i]
right = dp[i][j-1][1] + nums[j]
if left > right: #倒着推先手会选择更大的数
dp[i][j][0] = dp[i+1][j][1] + nums[i]
dp[i][j][1] = dp[i+1][j][0]
else:
dp[i][j][0] = dp[i][j-1][1] + nums[j]
dp[i][j][1] = dp[i][j-1][0]
i,j = dp[0][n-1]
return i-j >= 0
dp不考虑先后手的区别
甲乙比赛,甲先手面对区间[i…j]时,dp[i][j]表示甲对乙的净胜分。
最终求的就是,甲先手面对区间[0…n-1]时,甲对乙的净胜分dp[0][n-1]是否>=0。
甲先手面对区间[i…j]时,
如果甲拿nums[i],那么变成乙先手面对区间[i+1…j],这段区间内乙对甲的净胜分为dp[i+1][j];那么甲对乙的净胜分就应该是nums[i] - dp[i+1][j]。
如果甲拿nums[j],同理可得甲对乙的净胜分为是nums[j] - dp[i][j-1]。
以上两种情况二者取大即可。
def stoneGame(self, piles):
"""
:type piles: List[int]
:rtype: bool
"""
#定义dp为区间[i,j]某个人先手能取得的净胜分数
n = len(piles)
dp = [[0]*n for i in range(n)]
for i,pile in enumerate(piles):
dp[i][i] = pile
for i in range(n-2,-1,-1):
for j in range(i+1,n):
dp[i][j] = max(piles[i] - dp[i+1][j],piles[j]-dp[i][j-1])
return dp[0][n-1]>=0