题目:
解题思路:
一开始拿到题目想到思路就是两个人轮流拿石子只要保证每次拿到的石子不会导致已移除的所有石子的值之和能够被整除3即可。这一思路存在的问题就是忽略了最佳,就仅仅是保证了当下这一步自己不会输掉游戏但是并没有考虑对手以及整局游戏的走向。例如当遇到stones = {1, 1, 7, 10, 8, 17, 10, 20, 2, 10}的情况时就会发生错误。按照上面的解题思路,双方选取石子的顺序为:{1,1,8,10,20,10,17,7,2,10}这样就成了Bob胜利,而实际上如果A选择{8,17,20,2}中的一个然后再后续选择中保证不触发被3整除的条件那么必然会获得游戏的胜利。
上述思路已经可以说明存在缺陷并不适用于本题目,然后学习大佬的解题思路后发现这道题是使用博弈论来解决的。
首先如果直接对数组中的元素进行操作并不好处理,而根据题目我们可以通过将数组中的元素进行除3取余,将数组中的数分为若干个0 若干个1以及若干个2。0不会对结果造成任何的影响因此我们可以把0看做是换手操作。
-
首先当余数是0的个数为偶数个时,此时可以认为数组中不存在0,因此经过偶数次换手依旧会回到初始状态。
此时我们对1和2进行讨论,如果1或者2的数量有一个为0那么以1为例,A先选1,然后B再选1,再次到A依旧只能选1此时出发条件A输B胜。如果1的数量等于2的数量以{1,2}为例,那么A必胜。如果1和2的都存在并且数量相差为1那么A只需要先手选择数量较小的那个数即可,到B时他只能选择同样的数字,后续选择中A只要能选这个数字就选择这个数字即可,那么A必胜,以{1,1,1,2,2}为例,A先手选择2,那么B为了不输掉游戏只能选择2,后续A在选择1然后B只能选1那么就触发了条件A胜。经过分析当两个数字的数量差大于1时过程与这一过程类似因此也是A必胜。 -
如果当余数为0的个数为奇数个时,我们可以认为只有1个余数为0的数,同时容易发现A第一手选择不能选择余数为0的数字这样会直接导致游戏失败。这种情况下首先我们按照上述分析,若余数为1或者余数为2的数不存在,以{1,0}为例,B胜,但是此时如果{1,1,1,0}这种情况则会让A胜,因此这种分类不适用于余数为0的个数为奇数的情况。那么我们就需要重新找分类依据。通过观察可以发现当余数为1的个数与余数为2的个数相同时以{1,0,2}为例此时B胜,对数组规模进行扩充{1,1,1,2,2,2,0}此时依旧是B胜再次扩大结果依旧相同,因此我们可以考虑使用两者数量差作为分类条件。上述情况为两者的差为0,下一步就靠考虑两者的差为1{1,1,2,0},此时无论A开始选择1还是2只要B选择0那么B就会获得胜利,将规模再次扩充{1,1,1,1,2,2,2,0}此时依旧是如此,因此这种情况下B胜。当两者差值为2时以{1,1,0}为例,A只能选择1。此时B无论选择1或者0下次A选择都会导致数组选择完导致游戏结束B胜,再次进行扩充{1,1,1,1,2,2,0}此时情况依旧如此B必胜。当差值等于3时我们通过前面已知此时A必胜,因此当差值大于3时A必胜。
class Solution {
public boolean stoneGameIX(int[] stones) {
int[] flag = new int[3];
for(int i =0;i<stones.length;i++){
flag[stones[i]%3]++;
}
return flag[0]%2==0?!(flag[1]==0||flag[2]==0):!(Math.abs(flag[1]-flag[2])<=2);
//下面为具体分析过程
/* if(flag[0]%2==0){
if(flag[1]==0||flag[2]==0){
return false;
}
else{
return true;
}
}
else{
if(Math.abs(flag[1]-flag[2])<=2){
return false;
}
else{
return true;
}
}*/ }
}