原博客地址 https://blog.csdn.net/androidchanhao/article/details/81271077

题目链接

https://leetcode.com/problems/stone-game/discuss/

https://leetcode-cn.com/contest/weekly-contest-95/problems/stone-game/

877. 石子游戏

亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 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) 是奇数。

题解:

由于题目的限制条件是石头的堆数是偶数,且石头的总数是奇数,因此Alex可以选择一种策略总是选偶数堆或者奇数堆的石头,则一定可以胜过Lee。简单说,Alex在题目的条件限制下是必胜的。但这里我们需要进行更一般化的分析,例如石头堆数不一定是偶数,石头总数也不一定是奇数,且不但要判断Alex是否能赢,还要判断最多赢多少分,如果输,能不能提供最少输多少分。这里的分数是指多拿的石头数量。

我们每次只能拿两端的石头堆的石头,但我们又不知道拿完后剩下的石头堆的情况,因此我们考虑先解决子问题。例如我们求出2个相邻石头堆的胜负情况,我们可以根据求出的数据求出相邻3个石头堆的胜负情况,以此类推,我们可以根据n-1个相邻石头堆的胜负情况,求出n个相邻石头堆的胜负情况,即我们的原问题。

根据我们的类推我们可以设dp[i][j]piles[i]~piles[j]Alex最多可以赢Lee的分数。每次取石头堆只能从两端取,因此:dp[i][j] = max(piles[i] - dp[i+1][j], piles[j] - dp[i][j-1])。其中

piles[i] - dp[i+1][j]表示Alex取走i上的石头堆,piles[j] - dp[i][j-1]表示Alex取走的是j上的石头堆。注意,为什么dp[i+1][j]表示piles[i+1]~piles[j]之间Alex最多可以赢Lee的分数,而piles[i]要减去该值而不是加上该值呢?由于我们的要求是每一步Alex和Lee采取的都是最优策略,当取piles[i]时,piles[i+1]~piles[j]中Alex和Lee的走法会调换。意即Lee走Alex的走法,Alex走Lee的走法,因此这里要做减法。

以题目中的[5, 3, 4, 5]为例,下图是我们的计算步骤:

按照这个思路,很容易写出完整的代码:

class Solution {
public:
bool stoneGame(vector<int>& piles) {
int n = piles.size();
vector<vector<int>> dp(n, vector<int>(n, 0));
for(int i = 0; i < n; i++) {
dp[i][i] = piles[i]; //初始化只有i一个石头堆的情形
}
for(int dis = 1; dis < n; dis++) {//依次计算相邻2个石头堆到n个石头堆的情形
for(int i = 0; i < n - dis; i++) {
dp[i][i+dis] = max(piles[i]-dp[i+1][i+dis], piles[i+dis]-dp[i][i+dis-1]);
}
}
return dp[0][n-1] > 0;
}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

参考资料:

https://leetcode.com/problems/stone-game/discuss/154610/C++JavaPython-DP-or-Just-return-true

leetcode 877. Stone Game 详解 -——动态规划的更多相关文章

  1. 详解动态规划(Dynamic Programming)& 背包问题

    详解动态规划(Dynamic Programming)& 背包问题 引入 有序号为1~n这n项工作,每项工作在Si时间开始,在Ti时间结束.对于每项工作都可以选择参加与否.如果选择了参与,那么 ...

  2. [LeetCode] 877. Stone Game 石子游戏

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

  3. LeetCode刷题 字符串详解

    一.字符串常用的操作 1. string类 1.1 string的定义与初始化 1.1.1 string的定义 1.1.2 string的初始化 1.2 string的赋值与swap.大小操作.关系运 ...

  4. LeetCode 877. Stone Game

    原题链接在这里:https://leetcode.com/problems/stone-game/ 题目: Alex and Lee play a game with piles of stones. ...

  5. LeetCode 413 Arithmetic Slices详解

    这个开始自己做的动态规划复杂度达到了O(n), 是用的是2维的矩阵来存前面的数据,复杂度太高了, 虽然好理解,但是没效率,后面看这个博客发现没有动态规划做了这个题 也是比较厉害. 转载地址: http ...

  6. [LeetCode] 877. Stone Game == [LintCode] 396. Coins in a Line 3_hard tag: 区间Dynamic Programming, 博弈

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

  7. LeetCode 856 递归思路详解

    题目描述 给定一个平衡括号字符串 S,按下述规则计算该字符串的分数: () 得 1 分. AB 得 A + B 分,其中 A 和 B 是平衡括号字符串. (A) 得 2 * A 分,其中 A 是平衡括 ...

  8. LeetCode 392. Is Subsequence 详解

    题目详情 给定字符串 s 和 t ,判断 s 是否为 t 的子序列. 你可以认为 s 和 t 中仅包含英文小写字母.字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 & ...

  9. LeetCode 115.不同的子序列 详解

    题目详情 给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数. 一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串.(例如, ...

随机推荐

  1. 前端框架-jQuery自学笔记

    What's jQuery jq就是一个封装了很多方法的js库. Why use jQuery 原生js的缺点 不能添加多个入口函数(window.onload),如果添加多个,后面会把前面的覆盖 a ...

  2. STL源码剖析:迭代器

    准备知识 什么是迭代器? 迭代器是链接容器和算法的桥梁,所有的算法都通过迭代器操作容器中的数据 迭代器是一种智能指针,最重要的操作符重载就是operator*,operator-> 迭代器的实现 ...

  3. 题解 CF997E 【Good Subsegments】

    先将问题进行转化,发现满足\((max-min)-(r-l)=0\)的区间即为好区间. 对于本题这样的统计子区间的问题,先将询问离线,按右端点排序一个一个解决,固定右端点,然后通过数据结构来处理出区间 ...

  4. linux命令笔记记录(自用)

    1.解除yum锁定: sudo rm -rf /var/run/yum.pid 2.删除文件夹: rm -rf /var/log/httpd/access 3.更新pip: python -m pip ...

  5. git问题解决

    1.如果系统中有一些配置文件在服务器上做了配置修改,然后后续开发又新添加一些配置项的时候, 在发布这个配置文件的时候,会发生代码冲突: error: Your local changes to the ...

  6. Python快速入门PDF高清完整版免费下载|百度云盘

    百度云盘:Python快速入门PDF高清完整版免费下载 提取码:w5y8 内容简介 这是一本Python快速入门书,基于Python 3.6编写.本书分为4部分,第一部分讲解Python的基础知识,对 ...

  7. 旧的成功的AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="htt ...

  8. sed打印包含一个字符串的行到包含另一个字符串的行解答

    sed -n '/字符串1/,/字符串2/p' filename  这个命令为什么有时候打印不出来想要的东西,例如:sed -n '/root/,/adm/p'  /etc/passwd      我 ...

  9. 第九章 Lambda&方法引用

    9.1.Lambda表达式 9.1.1.标准格式 (形式参数) -> {代码块} 9.1.2.使用前提 有一个接口并且接口中有且仅有一个抽象方法 9.1.3.常见应用 9.1.3.1.无参无返回 ...

  10. Day15_redis安装及配置

    学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"乐优商城"获取视频和教程资料! b站在线视频 redi ...