大佬,牛!!!
- 题目:是一个博弈类型的题目,这个题目主要是思路比较难想。给你一堆石子,然后每次A、B两人每次从里面取一个。然后判断输赢。游戏规则:
- 如果这个人取出来以后,所有的取出之和是3的倍数,则这个人输了。
- 如果这个人取出来以后,没有棋子了,并且不是3的倍数,则一定是B赢。
- 如果A赢就返回true,B赢返回false。
- 思路:首先明确几点,肯定不是遍历所有情况,也无法遍历,因为每个人都是最聪明的,我们很难取找条件。所以题目一定是找规律。
- 首先,我们可以发现,每次取我们其实不用管这个数是多少,我们只需要关心这个数对3取余。因为这个才会影响胜负,这一点一定明确。然后就是找规律了。对3取余以后的情况有三种:0、1、2。因此下面我们值考虑余数。
- 我们先看0的时候,0其实改变了谁能多取一次,如果0的个数是偶数,则每个人取0的次数一样,如果是奇数,则B可以多选择一次这个0,并且不会输掉比赛。
- 然后就是关键了,我们让A赢,则一定是B输,而B只有一种情况会输,就是拿出来是3的倍数。
- 然后问题就简单了,我们想办法让B只能是拿出来是3的倍数就好了。
- 首先我们假设0的个数是偶数,则其实0在这里就没有什么意义了。
- 然后A先拿1,
- 则B一定是1,不然就输了,因此如果有只有一个1的时候,只要有一个2,A就赢了(也就是只有一个1,并且有2的时候,返回true)
- B能拿到1,当前情况为取了1、1,接下来要想一直下去A只能拿2、B只能拿1,序列为:112121…,这时候要想B输,则让B取不到1即可,这时候的条件是2的个数大于等于1的个数,并且前提是1的个数大于两个(因为,本条的前提是B能拿到一个1,并且A先拿的1,这里一共用了两个1)(也就是说1的个数大于两个,并且2的个数大于等于1的个数,返回true)。
- 然后看A先拿2,
- 则B一定是2,不然B就输了(也就是只有一个2,并且有1的时候,返回true)。
- 则B能拿到2,当前情况为取了2、2,接下来要想一直下去A只能拿1、B只能拿2,序列为221212…,这时候要想B输,则让B取不到2即可,这时候的条件是1的个数大于等于2的个数,并且前提是2的个数大于两个(因为,本条的前提是B能拿到一个2,并且A先拿的2,这里一共用了两个2)(也就是说2的个数大于两个,并且1的个数大于等于2的个数,返回true)。
- 然后看0是奇数的时候,也就是多一个0。
- A先拿1,
- 则B如果没有1,B还可以取一个0,然后由于A只能取1了,因此B是可以取1的。
- 序列为101212…,这时候要想B输,则B取不到2即可(只能取1),即1的个数大于等于2的个数+三
- 序列为112121…,这时候要想B输,则B取不到1即可,但是还能取0,则B取0,序列为112120,然后A只能取1,因此B能取到1。也就是这个0一定是由A来取,那直接构建一个序列110212…,但是要B输,取不到最后的2,也就是1的个数大于等于2的个数+三。
- 结论:1的个数大于等于2的个数+三,则A一定获胜
- 则B如果没有1,B还可以取一个0,然后由于A只能取1了,因此B是可以取1的。
- A先拿2,
- 结论相反:2的个数大于等于1的个数+三
- 技巧:
- 没有特别多的技巧,主要是思路。
- 使用余数进行,这个将余数个数放在一个数组中
伪代码
定义余数数组
遍历填写数组内容
如果0 的个数是偶数
四种情况会返回true
否则返回false
否则,0的个数是偶数
两种情况会返回true。
java代码
class Solution {
public boolean stoneGameIX(int[] stones) {
// 0会影响谁先手
int nums[] = new int[3];// 0,1,2的余数的个数
for (int i = 0; i < stones.length; i++) {
nums[stones[i] % 3]++;
}
if (nums[0] % 2 == 0) {// 0的个数是偶数
if (nums[1] == 1 && nums[2] >= 1) return true;// 余数是1的个数是1个,这时候要想A获胜,则余数是2的个数必须大于等于1
if (nums[1] >= 2 && nums[2] >= nums[1]) return true;// 余数大于等于2,这时候A想获胜,则余数是2的必须
if (nums[2] == 1 && nums[1] >= 1) return true;
if (nums[2] >= 2 && nums[1] >= nums[2]) return true;
return false;
} else {// 0的个数是奇数
return nums[2] - nums[1] >= 3 || nums[1] - nums[2] >= 3;
}
}
}
- 总结:这种博弈的题目一定是找规律,然后我们就让一个赢,站在一个人的角度上去想,找到所有情况以后,其余情况返回相反的结果即可。这里原文链接其实并不详细,主要是给了两个有规律的思路,在这里附一下链接。
代码优化,四种情况可以优化为如下代码
class Solution {
public boolean stoneGameIX(int[] stones) {
// 0会影响谁先手
int nums[] = new int[3];// 0,1,2的余数的个数
for (int i = 0; i < stones.length; i++) {
nums[stones[i] % 3]++;
}
if (nums[0] % 2 == 0) {// A先手
return nums[1] >= 1 && nums[2] >= 1;
} else {// 其实是b先手
return nums[2] - nums[1] >= 3 || nums[1] - nums[2] >= 3;
}
}
}