力扣解题思路:464. 我能赢吗

464. 我能赢吗

思路:在这里插入图片描述
乍一看又像是脑筋急转弯的题目,但是看标签发现竟然可以用动态规划,这个我觉得很难理解,看题解里有一个用递归写的,我觉得思路不错,记录一下:

public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
    int sum=0;
    for(int i=1;i<=maxChoosableInteger;i++) sum+=i;
    if(sum<desiredTotal) return false;//所有的数取完了仍然小于desiredTotal
    Map<Integer,Boolean> map = new HashMap<>();
    return canWin(maxChoosableInteger,desiredTotal,0,map);
}
public boolean canWin(int chooseable,int nowTarget,int used,Map<Integer,Boolean> map){
    if(map.containsKey(used)) return map.get(used);//判断是否计算过(记忆化递归)
    for(int i=1;i<=chooseable;i++)//我方选数
    {
        if((used & (1<<i)) == 0)//判断是否使用过该数(因为题目中说过maxChoosableInteger小于20《32,故可以用每一位代表该数是否被选用过)
        {
            if(nowTarget <= i || !canWin(chooseable,nowTarget-i,used | (1<<i),map))//一步即可赢||找到一步使对方无法赢
            {
                map.put(used,true);
                return true;
            }
        }
    }
    map.put(used,false);
    return false;
}

其主要代码部分就是记忆化递归,首先遍历所有的数作为起始数,为了防止重复遍历将所有数和对应结果保存在map中,以后遇到就不用再次递归而可以直接使用结果。

另外很重要的一点是,在递归的每一条路径上不可以使用重复的数字,为了记录此路径使用过的数字,他使用了一个比较巧妙的方法,因为题目中说过maxChoosableInteger小于20<32,故可以用每一位代表该数是否被选用过(之前某个题目也使用过类似的思路)

但其实最巧妙的是这一句:

if(nowTarget <= i || !canWin(chooseable,nowTarget-i,used | (1<<i),map))

通过这一句直接判断了对手的状态,实在是很巧妙~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值