博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[C++&Rust]LeetCode No.877 石子游戏(每日一题)
阅读量:4048 次
发布时间:2019-05-25

本文共 2321 字,大约阅读时间需要 7 分钟。

原贴地址:

题目

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

思路分析

这道题有许多思路。

我们选择两个最能考验思想的给大家讲一讲。

解法1-数学分析

首先是一个取巧的想法。在这种你取一颗,我取一颗的过程中,极有可能出现一种情况。假设有偶数个数字:

[0,1,2,3,4,5,6,7]
可以看出,头是偶数,尾是奇数,而且穿插排列,那么对于在这种状态下先手的人来说,他有一种策略,他可以拿到所有奇数或者偶数位的数字。具体的操作情况见下:
假设A先手。A想拿到所有偶数,A可以先拿0,这样在B选择的时候只剩1和7,都是奇数,而在B拿完一边之后,会露出来一个偶数2或者6,在这种情况下,A将该偶数拿走,剩下给B的又全部是奇数。
按照这个顺序,A 如果想,一定能拿到所有的偶数,那么B就被迫拿了所有的奇数,同理,A也可以选择拿到所有的奇数,那么B就被迫拿了所有的偶数。
在这种条件下,如果所有偶数位的和与奇数位的和不同,那么A就有必胜策略 ,而题目中的条件告诉我们,偶数位的和与奇数位的和相加是一个奇数,所以必定有一个大,有一个小,那么A一定有必胜策略
所以直接return true;就可以了
代码就懒得贴了。

解法2-动态规划

老方法,来个dp的模板

|递推公式|dp[i][j]=max(num[i]-dp[i+1][j],num[j]-dp[i][j-1])

–|
|边界条件|dp[i][i]=0,其余等于INT_MIN
|dp[i][j]的意义|边界范围包含[i,j]的子数组先手可以获得的最大分差

注意这个递推的时候不能按照常规的for (i…) for(j…)

会出错,因为我们的i,j不是按顺序递增的。
从递推公式可以看出,是一个典型的模拟过程,也就是说,如果有dp[i][j],且A是先手,A有两个选择,一个是选头,一个是选尾。
选头的话,剩下的数组就是[i+1][j],但此时对于B来说是先手,dp[i+1][j]的意义是B先手的情况下B可以获取的最大分差,所以我们应拿num[i]减去dp[i+1][j],才能获取A获取的最大分差。
选尾部的情况同理。

C++代码

class Solution {
public: bool stoneGame(vector
& piles) {
int n = piles.size(); vector
> dp(n, vector
(n, INT_MIN)); for (int i = 0; i < n; ++i) dp[i][i] = piles[i]; for (int len = 1; len < n; ++len) for (int i = 0; i + len < n; ++i) {
int j = i + len; dp[i][j]=max(piles[i]-dp[i+1][j],piles[j]-dp[i][j-1]); } return dp[0][n - 1] > 0; }};

Rust代码

impl Solution {    pub fn stone_game(piles: Vec
) -> bool { let n = piles.len(); let mut dp = vec![vec![i32::MIN; n]; n]; for i in 0..n { dp[i][i] = piles[i]; } for len in 1..n { for i in 0..(n - len) { let j = i + len; dp[i][j] = (piles[i] - dp[i + 1][j]).max(piles[j] - dp[i][j - 1]); } } dp[0][n - 1] > 0 }}

转载地址:http://juuci.baihongyu.com/

你可能感兴趣的文章
能源化工要怎么管控核心数据
查看>>
媒体广告业如何运用云盘提升效率
查看>>
企业如何运用企业云盘进行数字化转型-实现新发展
查看>>
司法如何运用电子智能化加快现代化建设
查看>>
iSecret&nbsp;1.1&nbsp;正在审核中
查看>>
IOS开发的开源库
查看>>
IOS开发的开源库
查看>>
Jenkins - sonarqube 代码审查
查看>>
Jenkins + Docker + SpringCloud 微服务持续集成(一)
查看>>
Jenkins + Docker + SpringCloud 微服务持续集成 - 单机部署(二)
查看>>
Jenkins + Docker + SpringCloud 微服务持续集成 - 高可用集群部署(三)
查看>>
Golang struct 指针引用用法(声明入门篇)
查看>>
Linux 粘滞位 suid sgid
查看>>
C#控件集DotNetBar安装及破解
查看>>
Winform皮肤控件IrisSkin4.dll使用
查看>>
Winform多线程
查看>>
C# 托管与非托管
查看>>
Node.js中的事件驱动编程详解
查看>>
mongodb 命令
查看>>
MongoDB基本使用
查看>>