算法分析(十):预测赢家

197 阅读2分钟

这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战

前言

  • 这道题目可谓是我比较难理解的题目了,因为我一直想不通为啥,直到看到了视频,自己敲击了一遍才理解。
  • 题目网址:leetcode-cn.com/problems/pr… 在这里插入图片描述

方法一:递归方法

  • 可以说这个方法是直接了当的模拟每个玩家的最优解,如图所示 在这里插入图片描述
  • 所以根据上图可以大致分为三种情况
  • 第一种只剩下一个值给你
  • 第二种只剩下两个值给你选,那就选其中最大一个
  • 第三种数组还有很多值,给前后两个值给你选,那就要分不同的情况,需要将两个取值的结果进行递归
  • 我们详细来说一下第三种情况,假设数组就是 1,5,233,7,再定义两个指针 l 和 r 分别指向1和7
    • 当你选择了 l 的时候 ,玩家二就只能选择 l+1 , r 这两个数
      • 如果他选择了 l + 1 ,那你只能选择 l+2 ,r 而这种时候就可以触发第二种情况
      • 如果他选择了r , 那你只能选择 l+1 , r-1 而这也可以触发第二种情况
  • 不知道你们发现没有,上面就已经形成了递归,根据这种思想就会形成下面的代码
class Solution {
    public boolean PredictTheWinner(int[] nums) {
        if(nums.length <= 1){
            return true;
        }
        int sum = 0;
        for(int i : nums){
            sum += i;
        }
        int s = maxSource(nums,0,nums.length -1);
        System.out.println(s);
        return s>=(sum-s);
    }

    public int maxSource(int[] arr, int l,int r){
        if(l==r){
            return arr[l];
        }
        int left = 0;
        int right = 0;
        if(r-l == 1){
            left = arr[l];
            right = arr[r];
        }
        if(r-l >= 2){
            left = arr[l] + Math.min(maxSource(arr,l+2,r), maxSource(arr,l+1,r-1));
            right = arr[r] + Math.min(maxSource(arr,l+1,r-1), maxSource(arr,l,r-2));
        }
        return Math.max(left,right);
    }
}

在这里插入图片描述

方法二:动态规划

  • 动态规划就是将递归的方法使用二维数组来模拟,并且之前模拟的最优解可以用二维数组来存贮

  • 首先创建一个二维数组,然后其行数和列数都等于数组的长度,dp[i][j] 表示当数组剩下的部分为下标 ii 到下标 jj 时,即在下标范围 [i, j] 中,当前玩家与另一个玩家的分数之差的最大值,注意当前玩家不一定是先手。

  • 只有当 i≤j 时,数组剩下的部分才有意义,因此当 i>j 时,dp[i][j]=0。

  • 当 i=j时,只剩一个数字,当前玩家只能拿取这个数字,因此对于所有 0≤i<nums.length,都有 dp[i][i]=nums[i]

  • 如下图所示 在这里插入图片描述

  • 当 i<ji<j 时,当前玩家可以选择nums[i] 或nums[j],然后轮到另一个玩家在数组剩下的部分选取数字。在两种方案中,当前玩家会选择最优的方案,使得自己的分数最大化。 在这里插入图片描述

  • 所以可以推出来 dp[i][j] = Math.max(num[i] - dp[i+1][j], num[j] - dp[i][j-1]) 这个状态方程

  • 就这样从后往前推,推出最后一个dp[0][3]看是否对于0,则可以看得出是否会赢。

class Solution {
    public boolean PredictTheWinner(int[] nums) {
        int length = nums.length;
        int[][] dp = new int[length][length];
        for(int i=0;i<length;i++){
            dp[i][i] = nums[i];
        }
        for(int i=length-2;i>=0;i--){
            for(int j=i+1;j<length;j++){
                dp[i][j] = Math.max(nums[i] - dp[i+1][j], nums[j] - dp[i][j-1]);
            }
        }
        return dp[0][length-1] >= 0;
    }
}

在这里插入图片描述

总结

  • 递归方法我懂了,但是不知道怎么说会比较清楚,所以看着很乱,动态规划本来是晕晕绕绕的,但是边写边想边画就理出来了。