首页 > 其他分享 >力扣-877-石子游戏

力扣-877-石子游戏

时间:2023-04-07 17:47:29浏览次数:42  
标签:end piles 877 石子 alice len 力扣 start dp

我尝试使用昨天猫鼠游戏的思路来解决这个博弈问题,也就是DFS

private:
	int alice, bob;// 用来分别计数两人手上的石子数量
public:
	bool dfs(vector<int>& piles, int start, int end, bool firstTurn) {
		// 用两个指针来标记剩余石子堆的起始/结束位置
		// 出口条件是:石子选完了,双方手上石子数量的情况
		if (start > end) {
			// 当石子都选完了
			if (alice > bob) return true;// alice手上石子更多则alice赢
			else return false;// 否则bob赢
		}
		// 模拟取石子的情况
		if (firstTurn) {
			// 从头取
			alice += piles[start];
			// 可达必败则必胜
			if (!dfs(piles, start + 1, end, !firstTurn))return true;
			alice -= piles[start];

			// 从头取
			alice += piles[end];
			// 可达必败则必胜
			if (!dfs(piles, start, end - 1, !firstTurn))return true;
			alice -= piles[end];
		}
		else {
			// 从头取
			bob += piles[start];
			// 可达必败则必胜
			if (!dfs(piles, start + 1, end, !firstTurn))return false;
			bob -= piles[start];

			// 从头取
			bob += piles[end];
			// 可达必败则必胜
			if (!dfs(piles, start, end - 1, !firstTurn))return false;
			bob -= piles[end];
		}

		return false;
	}

	bool stoneGame(vector<int>& piles) {
		// 两人分别从首位选取一堆石子,最后手上最多的赢
		// 可达必败则必胜
		// 只达必胜则必败
		// alice赢指的是alice必胜态,也就是说有可能赢就行
		// 那么bob赢就是指必败态
		return dfs(piles, 0, piles.size() - 1, true);
	}

在不考虑超时的情况下,这段代码是可以通过题目的,如果要解决超时问题

  1. 思路1是通过记忆化优化DFS,GPT给出的是memo[start][end][firstTurn]这样一个三维数组,我不是很理解,同时也觉得这过于复杂了
  2. 换个思路,使用动态规划

官解

官解中使用动态规划首先引入了一个概念:alice和bob手上石子数量的差值,因为如果想我上面那样有两个变量的话是没法动态规划的

动态规划三步走:

  1. dp数组的定义
    dp[i][j]表示从i位置到j位置,差值的最大值
    如果最大值小于0,则alice必输,retrun false,否则return true
    等于0不存在,因为石子是奇数
  2. dp数组初始化
    二维数组的行列数都是石子堆长度
    i<=j的时候dp[i][j]才是有意义的,于是对于i>j的情况都可以置0,不会对其他项产生影响
    i==j的时候,dp[i][j]只等于piles[i][j]
  3. 状态转移方程
    当前玩家可以从头/尾,即dp[i]和dp[j]中选择一个,并使得自己的石子数达到最大值

差值的最大值好理解,可是为什么是i位置到j位置呢?

	bool stoneGame(vector<int>& piles) {
		int len = piles.size();
		vector<vector<int>> dp(len,vector<int>(len,0));

		// 初始化dp数组
		for (int i = 0; i < len; i++) dp[i][i] = piles[i];

		// 注意这边的递推方向,i是从后往前,j是从前往后
		// i从len-2开始,[len-1][len-1]已经被初始化了,其他的[len-1][j]都是没有意义的
		for (int i = len-2; i >=0; i--) {
			// j>i才有意义
			for (int j = i+1; j < len; j++) {
				// 为什么这里是-可能的最大值?
				// 减去的是对方可能的最大值,也就是自己先手,对方后手的最大值
				dp[i][j] = max(piles[i]-dp[i+1][j], piles[j]-dp[i][j-1]);
			}
		}
		return dp[0][len - 1] > 0;
	}

空间优化不是很看得懂,下次再说

标签:end,piles,877,石子,alice,len,力扣,start,dp
From: https://www.cnblogs.com/yaocy/p/17296920.html

相关文章

  • 合并石子
    #include<iostream>#include<string.h>usingnamespacestd;constintN=310;intn;ints[N];intf[N][N];intmain(){scanf("%d",&n);memset(f,0x3f,sizeoff);for(inti=1;i<=n;i++){intx;......
  • 力扣1050(MySQL)-合作过至少三次的演员和导演(简单)
    题目:ActorDirector 表: 写一条SQL查询语句获取合作过至少三次的演员和导演的id对 (actor_id,director_id)示例:  建表语句:1createtableifnotexistsactordirector_1050(actor_idint(3),director_idint(3),timestampint(3)primarykey);2truncatetable......
  • 力扣1045(MySQL)-买下所有产品的客户(中等)
    题目:Customer 表: Product 表:写一条SQL查询语句,从 Customer 表中查询购买了 Product 表中所有产品的客户的id。示例:  解题思路:建表语句:1createtableifnotexistscustomer_1045(customer_idint(3)notnull,product_keyint(3));2createtableif......
  • 力扣627(MySQL)-变更性别(简单)
    题目:Salary 表:请你编写一个SQL查询来交换所有的'f'和'm'(即,将所有'f'变为'm',反之亦然),仅使用单个update语句,且不产生中间临时表。注意,你必须仅使用一条update语句,且不能使用select语句。查询结果如下例所示。示例1: 来源:力扣(LeetCode)链接:https://leet......
  • 力扣-93-复原IP地址
    直达链接之前我写过一次IP地址转二进制好吧,读完题发现好像和这题没什么关系给一串数字中加.,返回所有的能够构成合法IP地址的结果有点回溯的味道,但是却又和之前的排列组合不太一样:其实相当于划分4个空往里填数字,但是这里每个空中的数字长度是不确定的填入数字是会有额外的两......
  • 力扣 面试题 10.11. 峰与谷
    面试题10.11.峰与谷在一个整数数组中,“峰”是大于或等于相邻整数的元素,相应地,“谷”是小于或等于相邻整数的元素。例如,在数组{5,8,4,2,3,4,6}中,{8,6}是峰,{5,2}是谷。现在给定一个整数数组,将该数组按峰与谷的交替顺序排序。示例:输入:[5,3,1,2,3]输出: [......
  • 力扣 376. 摆动序列
    376.摆动序列如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。例如, [1,7,4,9,2,5] 是一个 摆动序列 ,因为差值 (6,-3,5,-7,3) ......
  • 力扣626(MySQL)-换座位(中等)
    题目:表: Seat编写SQL查询来交换每两个连续的学生的座位号。如果学生的数量是奇数,则最后一个学生的id不交换。按 id 升序 返回结果表。查询结果格式如下所示。示例1: 解释:请注意,如果学生人数为奇数,则不需要更换最后一名学生的座位。解题思路:①交换座位号是交换相......
  • 力扣620(MySQL)-有趣的电影(简单)
    题目:某城市开了一家新的电影院,吸引了很多人过来看电影。该电影院特别注意用户体验,专门有个LED显示板做电影推荐,上面公布着影评和相关电影描述。作为该电影院的信息部主管,您需要编写一个SQL查询,找出所有影片描述为非 boring (不无聊) 的并且id为奇数 的影片,结果请按等级......
  • 力扣619(MySQL)-只出现一次的最大数字(简单)
    题目:MyNumbers 表:单一数字是在MyNumbers表中只出现一次的数字。请你编写一个SQL查询来报告最大的单一数字。如果不存在单一数字,查询需报告null。查询结果如下例所示。示例1: 示例2: 来源:力扣(LeetCode)链接:https://leetcode.cn/problems/biggest-single-num......