给定一个表示分数的非负整数数组。 玩家 1 从数组任意一端拿取一个分数,随后玩家 2 继续从剩余数
    组任意一端拿取分数,然后玩家 1 拿,…… 。每次一个玩家只能拿取一个分数,分数被拿取之后不再可
    取。直到没有剩余分数可取时游戏结束。最终获得分数总和最多的玩家获胜。
    给定一个表示分数的数组,预测玩家1是否会成为赢家。你可以假设每个玩家的玩法都会使他的分数最
    大化。
    两个值的时候必然是取较大的,三个值,取一个能使自己分数和最大的,后手必然留较小的给先手,因
    此先手选一个值加上该较小值最大化

    1. static int maxScore(int[] nums, int l, int r) {
    2. //剩下一个值,只能取该值
    3. if (l == r) {
    4. return nums[l];
    5. }
    6. int selectLeft = 0;
    7. int selectRight = nums.length - 1;
    8. //剩下大于两个值,先手选一边(使自己得分最高的一边),后手则选使对手得分最低的一边
    9. if ((r - l) >= 2) {
    10. selectLeft = nums[l] +
    11. Math.min(maxScore(nums, l + 2, r), maxScore(nums, l + 1, r - 1));
    12. selectRight = nums[r] +
    13. Math.min(maxScore(nums, l + 1, r - 1), maxScore(nums, l, r - 2));
    14. }
    15. //剩下两个值,取较大的
    16. if ((r - l) == 1) {
    17. selectLeft = nums[l];
    18. selectRight = nums[r];
    19. }
    20. return Math.max(selectLeft, selectRight);
    21. }
    22. int getScore(int[] nums, int start, int end) {
    23. int selectLeft;
    24. int selectRight;
    25. int gap = end - start;
    26. if (gap == 0) {
    27. return nums[start];
    28. } else if (gap == 1) {
    29. // 此时直接取左右的值就可以
    30. selectLeft = nums[start];
    31. selectRight = nums[end];
    32. } else if (gap >= 2) {
    33. // 如果gap大于2,递归计算selectLeft和selectRight
    34. // 计算的过程为什么用min,因为要按照对手也是最聪明的来计算。
    35. int num = getScore(nums, start + 1, end - 1);
    36. selectLeft = nums[start] +
    37. min(getScore(nums, start + 2, end), num);
    38. selectRight = nums[end] + min(num, getScore(nums, start, end - 2));
    39. }
    40. return max(selectLeft, selectRight);
    41. }
    42. bool PredictTheWinner(int[] nums) {
    43. int sum = 0;
    44. for (int i : nums) {
    45. sum += i;
    46. }
    47. int player1 = getScore(nums, 0, nums.size() - 1);
    48. int player2 = sum - player1;
    49. // 如果最终两个玩家的分数相等,那么玩家 1 仍为赢家,所以是大于等于。
    50. return player1 >= player2;
    51. //return getScore(nums, 0, nums.size() - 1) >=0 ;
    52. }
    53. //差值
    54. int getScore(int[] nums, int start, int end) {
    55. if (end == start) {
    56. return nums[start];
    57. }
    58. int selectLeft = nums[start] - getScore(nums, start + 1, end);
    59. int selectRight = nums[end] - getScore(nums, start, end - 1);
    60. return max(selectLeft, selectRight);
    61. }

    动态规划:使用二维数组存储差值

    1. public boolean PredictTheWinner(int[] nums) {
    2. int length = nums.length;
    3. int[][] dp = new int[length][length];
    4. for (int i = 0; i < length; i++) {
    5. dp[i][i] = nums[i];
    6. }
    7. for (int i = length - 2; i >= 0; i--) {
    8. for (int j = i + 1; j < length; j++) {
    9. //j = i +1 因此可以优化为一维数组,下标位置相同才有值,据此推导其他的值
    10. //Math.max(nums[i] - dp[j][j], nums[j] - dp[j - 1][j - 1]);
    11. dp[i][j] = Math.max(nums[i] - dp[i + 1][j],
    12. nums[j] - dp[i][j - 1]);
    13. }
    14. }
    15. return dp[0][length - 1] >= 0;
    16. }