[Leetcode] 294. Flip Game II

  • Post author:
  • Post category:其他


这一题不太适合深究,目前来看适用的做法就只有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;
    }



版权声明:本文为chaochen1407原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。