[Leetcode] 294. Flip Game II

这一题不太适合深究,目前来看适用的做法就只有backtrack,外加一个memorization作为performance optimization。这一题返回true的条件是你走了某一步,对方完全没法赢,反过来说,你走了某一步,对方只要还有一种赢法你就得返回false。然而这对你和对方来说都是一样的。所以,canWin返回true的条件就是我们尝试了这一个flip,然后对方的canWin就返回了false。否则继续往下尝试,如果所有的尝试对方的canWin都返回了true,那么你这个canWin就只能是false。

这个backtrack还比较tricky的一点就是,第一个递归层是你的,第二个递归层是对方的,第三个递归层是你的,第四个是对方的...所以,这个递归层是否为true,是得取决于下一个递归层的返回值的取反。但是基本概念就是上面讲的那样。不停尝试,然后看看对方的canWin返回什么,返回false就直接返回true,如果走到底了都无法返回一个true,那就表示你没有必胜法,只能返回False。

根据上述算法,得到代码如下:

    public boolean canWin(String s) {
        return _canWin(s.toCharArray());
    }
    
    private boolean _canWin(char[] chArr) {
        for (int i = 0; i < chArr.length - 1; i++) {
            if (chArr[i] == '+' && chArr[i] == chArr[i + 1]) {
                chArr[i] = chArr[i + 1] = '-';
                if (!_canWin(chArr)) {
                    chArr[i] = chArr[i + 1] = '+';
                    return true;
                }
                chArr[i] = chArr[i + 1] = '+';
            }
        }

        return false;
    }

我们说了,memorization可以提高效率,原因在于不停的走法的combination可能会走出同样的string,这个时候就没有必要继续recursion下去了,如果走过了的话,所以可以用一个HashMap来进行节支。来记录当前的string和它的对应结果。

    public boolean canWin(String s) {
        return _canWin(s.toCharArray(), new HashMap<>());
    }
    
    private boolean _canWin(char[] chArr, HashMap<String, Boolean> cache) {
        String s = new String(chArr);
        if (cache.containsKey(s)) return cache.get(s);

        boolean result = false;
        for (int i = 0; i < chArr.length - 1 && !result; i++) {
            if (chArr[i] == '+' && chArr[i] == chArr[i + 1]) {
                chArr[i] = chArr[i + 1] = '-';
                if (!_canWin(chArr, cache)) {
                    result = true;
                }
                chArr[i] = chArr[i + 1] = '+';
            }
        }

        cache.put(new String(chArr), result);
        return result;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值