力扣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; } }