力扣486-预测赢家-(dp)

https://leetcode-cn.com/problems/predict-the-winner

题意:给一个长度为n的正数数组a,两个人轮流取数,每人每次可以在左右两端取一个数字,谁累计得多谁赢。判断先手是否能赢。

思路:

设自己的收益为x,别人的收益为y,纯收益就是x-y,如果纯收益大于0,就能赢。

贪心取最大值显然不行,(6,100,1,1)这样先手先取第一个就GG了。

对一段数,区间[i,j]每取一个数,不论是哪边,都会对后面造成影响。

取了i,收益a[i],剩下[i+1,j]给对方取。

取了j,收益a[j],剩下[i,j-1]给对方取。

如果只有1个数,那么选取的人 的最大收益 是一定的

如果只有2个数,一人一个,先手的最大收益也是一定的,纯收益=max-min。

如果有3个数,不论先选哪一个,后手选的时候只剩2个数,后手的最大收益也是一定的,第三次操作的收益也是固定的。

由此可见,对于每一种情况都可以逆推回来。

dp[i][j]表示 当前选手(无论是谁)对区间[i,j]能够获得的最大收益。

选取i,dp[i][j]=a[i]-dp[i+1][j];

选取j,dp[i][j]=a[j]-dp[i][j-1];

从i+1和j-1可以知道,双重循环i递增,j递减。

class Solution {
    public boolean PredictTheWinner(int[] a) {
        int[][] dp=new int[25][25];
        int n=a.length-1;
        for(int i=n;i>=0;i--){//下面需要利用到i+1,所以i要从大到小
            for(int j=i+1;j<=n;j++){//下面利用到j-1,所以j从小到大
                //区间[i,j]
                int x=a[i]-dp[i+1][j];//取i
                int y=a[j]-dp[i][j-1];//取j
                dp[i][j]=Math.max(x,y);
            }
        }
        if(dp[0][n]>=0)
            return true;
        else 
            return false;
    }
}

 

posted @ 2020-04-06 20:24  守林鸟  阅读(269)  评论(0编辑  收藏  举报