Leetcode之动态规划(DP)专题-877. 石子游戏(Stone Game)
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 。
提示:
2 <= piles.length <= 500
piles.length
是偶数。1 <= piles[i] <= 500
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)的更多相关文章
- leetcode 877. 石子游戏
题目描述: 亚历克斯和李用几堆石子在做游戏.偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] . 游戏以谁手中的石子最多来决出胜负.石子的总数是奇数,所以没有平局. 亚历克斯和李轮流进行,亚 ...
- 动态规划dp专题练习
貌似开坑还挺好玩的...开一个来玩玩=v=... 正好自己dp不是很熟悉,就开个坑来练练吧...先练个50题?小目标... 好像有点多啊QAQ 既然是开坑,之前写的都不要了! 50/50 1.洛谷P3 ...
- [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, ...
- Leetcode之动态规划(DP)专题-486. 预测赢家(Predict the Winner)
Leetcode之动态规划(DP)专题-486. 预测赢家(Predict the Winner) 给定一个表示分数的非负整数数组. 玩家1从数组任意一端拿取一个分数,随后玩家2继续从剩余数组任意一端 ...
- Leetcode之动态规划(DP)专题-1025. 除数博弈(Divisor Game)
Leetcode之动态规划(DP)专题-1025. 除数博弈(Divisor Game) 爱丽丝和鲍勃一起玩游戏,他们轮流行动.爱丽丝先手开局. 最初,黑板上有一个数字 N .在每个玩家的回合,玩家需 ...
- Leetcode之动态规划(DP)专题-详解983. 最低票价(Minimum Cost For Tickets)
Leetcode之动态规划(DP)专题-983. 最低票价(Minimum Cost For Tickets) 在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行.在接下来的一年里,你要旅行的 ...
- Leetcode之动态规划(DP)专题-647. 回文子串(Palindromic Substrings)
Leetcode之动态规划(DP)专题-647. 回文子串(Palindromic Substrings) 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串. 具有不同开始位置或结束位置的子 ...
- Leetcode之动态规划(DP)专题-474. 一和零(Ones and Zeroes)
Leetcode之动态规划(DP)专题-474. 一和零(Ones and Zeroes) 在计算机界中,我们总是追求用有限的资源获取最大的收益. 现在,假设你分别支配着 m 个 0 和 n 个 1. ...
- Leetcode之动态规划(DP)专题-264. 丑数 II(Ugly Number II)
Leetcode之动态规划(DP)专题-264. 丑数 II(Ugly Number II) 编写一个程序,找出第 n 个丑数. 丑数就是只包含质因数 2, 3, 5 的正整数. 示例: 输入: n ...
随机推荐
- springboot打包后静态资源webapp文件夹无法打包进去
1.如下图的目录结构 webapp 文件夹和resources 文件夹同级.使用mvn clean install 打包过后项目启动访问,静态资源页面404. 2.原因,springboot 打包时候 ...
- 激活函数matlab代码
[转自:http://blog.csdn.net/fendoubasaonian/article/details/52974608] %JOINT Summary of this function g ...
- ESP8266常见问题汇总——转载自官网
ESP8266 常见问题 本页面收集esp8266常见问题 概述 本文档主要介绍开发者在ESP8266开发中常见的一些问题. 这些问题主要包括以下几大类: 基本概念相关 ESP8266 相关 AiCl ...
- C#静态变量 总结
在C#程序中,没有全局变量的概念,这意味着所有的成员变量只有该类的实例才能操作这些数据,这起到了“信息隐藏”的作用.但有些时候,这样做却不是个明智的选择. 假设我们要定义一个图书类,要求该类能保存图书 ...
- Javascript调试技巧整理
整理一下网上看到的实用调试技巧! 1. 不要使用alert 首先,alert只能打印出字符串,如果打印的对象不是String,则会调用toString()方法将该对象转成字符串(比如转成[object ...
- From 7.8 To 7.14
From 7.8 To 7.14 大纲 学科 英语的话每天早上背单词, 争取每天做一篇完型, 一篇阅读, 一篇短文填空, 一篇改错, 一篇七选五??? 似乎太多了, 先试一下吧 语文的话, 尝试翻译一 ...
- finally应用
finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下. 之前在写爬虫的时候数据 ...
- 对opencv读取的图片进行像素调整(1080, 1920) 1.cv2.VideoCapture(构造图片读取) 2.cv2.nameWindow(构建视频显示的窗口) 3.cv2.setWindowProperty(设置图片窗口的像素) 4.video_capture(对图片像素进行设置)
1. cv2.VideoCapture(0) #构建视频抓捕器 参数说明:0表示需要启动的摄像头,这里也可以写视频的路径 2. cv2.nameWindow(name, cv2.WINDOW_NORM ...
- 哨兵模式java实例
/** * 测试Redis哨兵模式 * @author liu */ public class TestSentinels { @SuppressWarnings("resource&quo ...
- JxBrowser开启调试模式,JxBrowser debug
原文: 一.问题描述 像一般的浏览器都带了调试功能,按F12就能打开,在JxBrowser中如何开启调试模式了. 二.解决方法 以下代码就能开启调试模式: import com.teamdev.jxb ...