Leetcode之动态规划(DP)专题-877. 石子游戏(Stone Game)


亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。

游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。

亚历克斯和李轮流进行,亚历克斯先开始。 每回合,玩家从行的开始或结束处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。

假设亚历克斯和李都发挥出最佳水平,当亚历克斯赢得比赛时返回 true ,当李赢得比赛时返回 false 。

示例:

输入:[5,3,4,5]
输出:true
解释:
亚历克斯先开始,只能拿前 5 颗或后 5 颗石子 。
假设他取了前 5 颗,这一行就变成了 [3,4,5] 。
如果李拿走前 3 颗,那么剩下的是 [4,5],亚历克斯拿走后 5 颗赢得 10 分。
如果李拿走后 5 颗,那么剩下的是 [3,4],亚历克斯拿走后 4 颗赢得 9 分。
这表明,取前 5 颗石子对亚历克斯来说是一个胜利的举动,所以我们返回 true 。

提示:

  1. 2 <= piles.length <= 500
  2. piles.length 是偶数。
  3. 1 <= piles[i] <= 500
  4. sum(piles) 是奇数。

数学题,但我们用DP来求解这一题。

我们首先定义一个类,名为P:

private static class P {
int fir, sec; P(int fir, int sec) {
this.fir = fir;
this.sec = sec;
}
}

P中有两个属性,fir代表先手获得的最高分数,sec代表后手获得的最高分数

那么我们就可以写出DP的含义

我们把dp定义为2维,如dp[i][j]代表从这堆石子的第i堆选到第j堆中获得的最高分数。

那么dp[i][j].fir 表示从第i堆到第j堆中先手获得的最高分。

dp[i][j].sec 表示从第i堆到第j堆中后手获得的最高分。

例如:piles = [5,3,4,5]

dp[0][1].fir = 5, 面对[5,3],先手可以得5分

dp[0][1].sec = 3,面对[5,3],后手可以得3分

我们首先明确一点,当 i == j 时,即只有一堆石子的时候,上面的例子,例如 i == j == 0 那么 dp[i][j].fir = 5 sec=0

所以我们把i==j时的所有情况,遍历一遍。

for (int i = 0; i < n; i++) {
dp[i][i].fir = piles[i];
dp[i][i].sec = 0;
}

下面看一张图,是最终dp数组的最后状态:

我们可以看到,dp[0][1] = (9,3)    即dp[0][1].fir = 9    sec=3

这个数值是由(0,0)和(1,1)一起生成的。

我们可以按层遍历,即:

第1层:对角线

第2层:(9,3) (9,1) (2,1)

第3层:(4,9) (10,2)

第4层:(11,4)

选择了按层遍历后,我们需要得到状态转移方程:

面对一堆石头,我们有如下情况可以选择:

1、我是先手

  • 我选左边,面对剩下的piles[i+1,j]
  • 我选右边,面对剩下的piles[i,j-1]

随后对方变成先手,我变成后手

dp[i][j].fir = max(piles[i]+dp[i+1][j].sec,piles[j]+dp[i][j-1].sec);

2、我是后手

  • 先手选择了左边的那堆,我只能选择剩下的,dp[i][j].sec = dp[i+1][j].fir;
  • 先手选择了右边的那堆,我只能选择剩下的,dp[i][j].sec = dp[i][j-1].fir;

随后对方变成后手,我变成了先手


class Solution {
private static class P {
int fir, sec; P(int fir, int sec) {
this.fir = fir;
this.sec = sec;
}
} public boolean stoneGame(int[] piles) { int n = piles.length;
P[][] dp = new P[n + 1][n + 1];
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
dp[i][j] = new P(0, 0);
}
}
for (int i = 0; i < n; i++) {
dp[i][i].fir = piles[i];
dp[i][i].sec = 0;
} for (int c = 2; c <= n; c++) {
for (int i = 0; i <= n - c; i++) {
int j = c + i - 1;
int left = piles[i] + dp[i + 1][j].sec;
int right = piles[j] + dp[i][j - 1].sec;
if (left > right) {
dp[i][j].fir = left;
dp[i][j].sec = dp[i + 1][j].fir;
} else {
dp[i][j].fir = right;
dp[i][j].sec = dp[i][j - 1].fir;
} }
}
return dp[0][n - 1].fir > dp[0][n - 1].sec;
}
}

#本题思路来自题解区

Leetcode之动态规划(DP)专题-877. 石子游戏(Stone Game)的更多相关文章

  1. leetcode 877. 石子游戏

    题目描述: 亚历克斯和李用几堆石子在做游戏.偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] . 游戏以谁手中的石子最多来决出胜负.石子的总数是奇数,所以没有平局. 亚历克斯和李轮流进行,亚 ...

  2. 动态规划dp专题练习

    貌似开坑还挺好玩的...开一个来玩玩=v=... 正好自己dp不是很熟悉,就开个坑来练练吧...先练个50题?小目标... 好像有点多啊QAQ 既然是开坑,之前写的都不要了! 50/50 1.洛谷P3 ...

  3. [Swift]LeetCode877. 石子游戏 | Stone Game

    Alex and Lee play a game with piles of stones.  There are an even number of piles arranged in a row, ...

  4. Leetcode之动态规划(DP)专题-486. 预测赢家(Predict the Winner)

    Leetcode之动态规划(DP)专题-486. 预测赢家(Predict the Winner) 给定一个表示分数的非负整数数组. 玩家1从数组任意一端拿取一个分数,随后玩家2继续从剩余数组任意一端 ...

  5. Leetcode之动态规划(DP)专题-1025. 除数博弈(Divisor Game)

    Leetcode之动态规划(DP)专题-1025. 除数博弈(Divisor Game) 爱丽丝和鲍勃一起玩游戏,他们轮流行动.爱丽丝先手开局. 最初,黑板上有一个数字 N .在每个玩家的回合,玩家需 ...

  6. Leetcode之动态规划(DP)专题-详解983. 最低票价(Minimum Cost For Tickets)

    Leetcode之动态规划(DP)专题-983. 最低票价(Minimum Cost For Tickets) 在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行.在接下来的一年里,你要旅行的 ...

  7. Leetcode之动态规划(DP)专题-647. 回文子串(Palindromic Substrings)

    Leetcode之动态规划(DP)专题-647. 回文子串(Palindromic Substrings) 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串. 具有不同开始位置或结束位置的子 ...

  8. Leetcode之动态规划(DP)专题-474. 一和零(Ones and Zeroes)

    Leetcode之动态规划(DP)专题-474. 一和零(Ones and Zeroes) 在计算机界中,我们总是追求用有限的资源获取最大的收益. 现在,假设你分别支配着 m 个 0 和 n 个 1. ...

  9. Leetcode之动态规划(DP)专题-264. 丑数 II(Ugly Number II)

    Leetcode之动态规划(DP)专题-264. 丑数 II(Ugly Number II) 编写一个程序,找出第 n 个丑数. 丑数就是只包含质因数 2, 3, 5 的正整数. 示例: 输入: n ...

随机推荐

  1. 【转】用win7(64位)远程桌面连接linux(Ubuntu14.04)详细教程

    转自:http://blog.csdn.net/qq754438390/article/details/50042511 亲测,确实是可以.非常感谢原博. 用win7(64位)远程桌面连接linux( ...

  2. hive日期函数-杂谈(一)

    来到广发返现由于历史遗留问题很多时间格式十分杂乱 我将总结一下时间日期的事情 1.hive原生时间函数的功能 2.一些基本业务时间范围的指标的sql案例 3.自定义udf函数让后来人更方便

  3. if语句分析

    1.if语句的反汇编判断 if语句反汇编后的标志:     执行各类影响标志位的指令             jxx xxxx 如果遇到上面的指令,则很可能是if语句:   例如:     1.案例一 ...

  4. [Linux]ubuntu16.04 nginx彻底删除与重新安装

    nginx彻底删除与重新安装 查看nginx正在运行的进程,如果有就kill掉 sudo netstat -ntlp | grep nginx sudo kill -9 进程id 删除nginx,pu ...

  5. .Net中手动实现AOP

    序言 资料 https://www.cnblogs.com/farb/p/AopImplementationTypes.html

  6. [JOI2012春季合宿]Constellation (凸包)

    题意 题解 神仙结论题. 结论: 一个点集合法当且仅当其凸包上的两种颜色点分别连续. 证明: 必要性显然. 充分性: 考虑对于一个不同色三角形\(ABC\),不妨设点\(A\)为白点,点\(B,C\) ...

  7. Ansible常用模块之命令类模块

    Command模块 在远程节点上执行命令 [root@tiandong ~]# ansible all -m command -a "ls" 在远程主机上执行ls命令. [root ...

  8. Springdata-Jpa学习笔记

    Respository接口 Respository是Springdata JPA中的顶层接口,提供了两种查询方法: 1)基于方法名称命名规则 2)基于@Qeury注解查询 1. 方法名称命名规则查询 ...

  9. Linux 常用命令之df du

    1.du 命令:显示每个文件或目录的磁盘使用空间 1) du -h --max-depth [root@ip101 app]# pwd /opt/app [root@ip101 app]# du -h ...

  10. [学习笔记] Uplift Decision Tree With KL Divergence

    Uplift Decision Tree With KL Divergence Intro Uplift model 我没找到一个合适的翻译,这方法主要应用是,探究用户在给予一定激励之后的表现,也就是 ...