二刷464. Can I Win

这个题虽然做过一次,但再次做基本是没思路的。说明解法在第一次时应该是感觉比较另类不通用的。确实也如此:

这道题比较特别的地方是用一个int数组state来记录哪些数已经被用过,哪些数没有,然后map里面做记忆化搜索时用string来代表这个state, String curtState = Arrays.toString(state);这个方法可以说是非常巧妙。剩下的其实就是dfs+backtracking了。值得注意的是,当返回true的时候仍然要回溯,因为这不像有的dfs找到为true的时候就算是结束了,直接返回结果就可以。这道题其实我们在寻找那些可以win的所有状态,所以我们会把map里对应的所有状态都找到ture还是false,相当于是要去试for循环能到的所有中间状态。这种情况我们就算是找到了win的状态,也要回溯,在当下这一步return true,填充map, 继续for 循环。

二刷464. Can I Win_第1张图片
image.png
class Solution {
    public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
        if (desiredTotal <= 0){
            return true;
        }
        if ((1+maxChoosableInteger)*maxChoosableInteger/2 < desiredTotal){
            return false;
        }
        int[] state = new int[maxChoosableInteger+1];
        Map map = new HashMap<>();
        return helper(maxChoosableInteger, desiredTotal, state, map);        
    }
    
    private boolean helper(int maxChoosableInteger, int desiredTotal, int[] state, Map map){
        String curtState = Arrays.toString(state);
        if (!map.containsKey(curtState)){
            for (int i = 1; i < state.length; i++){
                if (state[i] == 0){
                    state[i] = 1;
                    if (desiredTotal - i <= 0 || !helper(maxChoosableInteger, desiredTotal - i, state, map)){
                        map.put(curtState, true);
                        state[i] = 0;
                        return true;
                    }
                    state[i] = 0;
                }
            }
            map.put(curtState, false);
        } 
        return map.get(curtState);
    }
}

你可能感兴趣的:(二刷464. Can I Win)