枚举法

枚举法与它的马甲们

DFS + Backtracking 的搜索量很大。如果每次 DFS 之前都要进行条件检查的话,优化条件函数可以显著提升程序速度。如 N-Queensarrow-up-rightPalindrome Partitioningarrow-up-right 还有 Sudoku Solverarrow-up-right

Too trivial. 这题和二叉树其实挺像的,因为在每一个位置都只有两种可能 "(" 和 ")".

 public class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> list = new ArrayList<String>();

        dfs(list, new StringBuilder(), n, n);

        return list;
    }

    private void dfs(List<String> list, StringBuilder sb, int left, int right){
        if(left == 0 && right == 0){
            list.add(sb.toString());
            return;
        }

        int length = sb.length();

        if(left > 0){
            sb.append('(');
            dfs(list, sb, left - 1, right);
            sb.setLength(length);
        }    

        if(right > left){
            sb.append(')');
            dfs(list, sb, left, right - 1);
            sb.setLength(length);
        }

    }
}

依旧是 DFS + Backtracking,每一步有三种可能:选一位数,两位数,还有三位数。

一个需要注意的边界条件是当选取多位数时,第一位不能是0,因为 '020' 或 '05' 都不是有效的 IP 地址。

当 DFS 的可能性比较多,而且只在 index 上有区别的时候,用 for 循环就好了。

一个比较简单暴力的搜索办法就是直接 DFS + Backtracking,每一步上需要考虑的字问题数量和当前字符串剩余长度相等。 这个解法是过不了 LeetCode OJ 的,会超时。

于是发现每次都要跑一个 isPalindrome() 太耗时间了,同一个字符串会被检查很多次,不如用 DP 把任意两个 index 之间的字符串缓存下,加速 isPalindrome() 的验证。

然并卵,还是超时。

主要原因在于,从每一个字符作为起点向两边扩张的赋值方式,还是不够快。

于是就有了这段代码,思路参考了 LeetCode 论坛,里面的小伙伴们好机智啊。

dp[i][j] 代表从index i ~ j 的字符串是不是 palindrome. dp[i][j] = dp[j][i].

其实也可以只填 dp[i][j],也就是矩阵的 lower half 三角形,不过到时候调用的时候要注意放 index 的先后顺序,不然结果会错。求稳的话,就一次都设一样的吧。

(7/6 号) 回头复习过程中发现,这就是做 search 类题,遇到了记忆化搜索啊。

在 palindrome 问题中,子串之间有天然的 optimal substructure,很适合利用 dp 做预处理解决。

建立一个 String 的所有 substring 是否为 palindrome 的矩阵,时间复杂度为等差数列,约为 0.5n20.5 n^2 (矩阵沿对角线划分的一半区域)

有个小地方要注意,终止条件是

而不是

不然在 test case 为 “22” 的时候在返回了所有正确答案之后会多出来一组 "a","b","c"

Last updated