动态规划:逐步优化,逐层递进,力扣486. 预测赢家

1、题目描述:

动态规划:逐步优化,逐层递进,力扣486. 预测赢家_第1张图片
动态规划:逐步优化,逐层递进,力扣486. 预测赢家_第2张图片

2、题解:

做完这题,可以做一下力扣887题石子游戏,基本上套路是一样的。
方法:动态规划:
这次从递归开始到记忆化递归,再到动态规划
动态规划问题,弄清楚三点:
1、重复子问题;
2、最优子结构;
3、无后效性。

动态规划:
1、状态定义;
2、状态转移方程;
3、初始化;base case
4、输出;
5、思考状态压缩。

可以用递归去求,但是会存在重叠子问题,加个备忘录可以解决重复问题。
方法1:递归:

定义一个helper()函数,功能是返回数组[i:j]之间当前做选择的玩家赢过对手的分数。如果大于零,
则代表他在这个子问题中赢了。
递归函数内部:当前选择的分数,减去,往后对手赢过自己的分数(剩余数组的递归结果)。因为选择有两种,
所以在两个差值中取较大的。

代码如下:

class Solution:
    def PredictTheWinner(self, nums: List[int]) -> bool:
        #递归
        def helper(i,j): #i,j为两端的索引
            if i == j: #递归出口,只有一个元素时
                return nums[i]
            left = nums[i] - helper(i+1,j) #选择左端
            right = nums[j] - helper(i,j-1) #选择右端
            return max(left,right) #取较大值
        return helper(0,len(nums) - 1) >= 0

方法2:记忆化递归:递归+备忘录
如果不加备忘录,会有重复子问题,因此,加备忘录
代码如下:

class Solution:
    def PredictTheWinner(self, nums: List[int]) -> bool:
        #记忆化递归
        n = len(nums)
        memo = [[None] * n for i in range(n)]
        def helper(i,j):
            if memo[i][j] != None:
                return memo[i][j]
            if i == j:
                memo[i][j] = nums[i]
                return nums[i]
            left = nums[i] - helper(i+1,j)
            right = nums[j] - helper(i,j-1)
            memo[i][j] = max(left,right)
            return memo[i][j]
        return helper(0,n-1) >= 0

方法3:动态规划:

状态定义:
	p[i][[j]:当前玩家在数组[i:j]中先手,赢过对方的分数
状态转移方程:
    d[i][j] = max(nums[i] - dp[i+1][j], nums[j] - dp[i][j-1])
    dp table的方向是由下往上,由左往右
base case:
    也就是只考虑表的右上角,初始值是对角线上的值为数组中相应值,即dp[i][i] = nums[i]

代码如下:

class Solution:
    def PredictTheWinner(self, nums: List[int]) -> bool:
        #动态规划
        n = len(nums)
        dp = [[0] * n for _ in range(n)]
        #base case
        for i in range(n):
            dp[i][i] = nums[i]
        for i in range(n-2,-1,-1):
            for j in range(i+1,n):
                left = nums[i] - dp[i+1][j]
                right = nums[j] - dp[i][j-1]
                dp[i][j] = max(left,right)
        return dp[0][n-1] >= 0

方法4:优化:状态压缩

class Solution:
    def PredictTheWinner(self, nums: List[int]) -> bool:
        #动态规划,状态压缩
        n = len(nums)
        dp = [0] * n
        #base case
        for i in range(n):
            dp[i]= nums[i]
        for i in range(n-2,-1,-1):
            for j in range(i+1,n):
                left = nums[i] - dp[j]
                right = nums[j] - dp[j-1]
                dp[j] = max(left,right)
        return dp[n-1] >= 0

3、复杂度分析:

方法1:
时间复杂度:O(N^2),N是数组的长度
空间复杂度:O(N),栈空间
方法2:
时间复杂度:O(N^2),N是数组的长度
空间复杂度:O(N^2), 备忘录的大小
方法3:
时间复杂度:O(N^2),N是数组的长度
空间复杂度:O(N^2)
方法4:
时间复杂度:O(N^2),N是数组的长度
空间复杂度:O(N)

你可能感兴趣的:(LeetCode高频面试题)