leetcode:22. Generate Parentheses

22. Generate Parentheses

  • 1. 题目描述
  • 2. 题目解答
  • 3. 如何写出这道题目

1. 题目描述

Given n pairs of parentheses, write a function to generate all combinations of 
well-formed parentheses.

Example 1:

Input: n = 3
Output: ["((()))","(()())","(())()","()(())","()()()"]

Example 2:

Input: n = 1
Output: ["()"]

Constraints:

1 <= n <= 8

2. 题目解答

  符合官方答案时间复杂度的代码如下所示:

class Solution {
public:
    vector<string> generateParenthesis(int n) {
        vector<string> res;
        int open = 0, close = 0, max = n;
        cases("", res, open, close, max, 2*n);
        return res;
    }
private:
    void cases(string pref, vector<string> &res, int open, int close, int max, int left){
        if(left == 0){
            res.push_back(pref);
            return;
        }
        if(open < max){
            cases(pref + "(", res, open + 1, close, max, left - 1); 
        }
        if(close < open){
            cases(pref + ")", res, open, close + 1, max, left - 1);
        }
    }
};

  起初的代码如下所示:

class Solution {
public:
    vector<string> generateParenthesis(int n) {
        vector<string> res;
        vector<string> result;
        cases("", res, 2*n);
        for(auto r : res){
            if(isok(r))
                result.push_back(r);
        }
        return result;
    }
private:
    void cases(string pref, vector<string> &res, int left){
        if(left == 0){
            res.push_back(pref);
            return;
        }
        cases(pref + "(", res, left - 1);
        cases(pref + ")", res, left - 1);
    }

    bool isok(string s){
        stack<char> sk;
        for(int i = 0; i < s.size(); ++i){
            if(!sk.empty() && hit(sk.top(), s[i])){
                sk.pop();
            }
            else{
                sk.push(s[i]);
            }
        }
        return sk.empty();
    }
    
    bool hit(char a, char b){
        if(a == '(' && b == ')')
            return true;
        return false;
    }
};

3. 如何写出这道题目

  感觉面试的过程中,如果写不出来最优解答。写出上述第二种方案,我感觉至少可以体现自己的基本功还算比较扎实,这里的基本功涉及到两方面:1是如何用代码实现数学中的组合;2是如何利用stack来对付“俄罗斯方块”或"接竹竿"问题。第一点的实现,注意将"前缀"不断的叠加传入,并将result也以引用的方式传入。第二点的实现,则是另外一道easy题目的简化。
  如何想在面试中写出最优方案,其关键点在于找到一种更加快速的判断字符串是否valid的方式,在“组合”的过程中及时early stop。这种更加快速判断的方式就是:如果在字符串成长的过程中,open括号的数量始终小于等于n, 且close括号的数量始终小于等于open括号的数量,且最终open括号的数量等于close括号的数量。则为有效。这个是断言是valid的充分必要条件。我们可以根据该断言的必要性来及时early stop, 根据该断言的充分性做最终的方案收集。就可以形成上述最优 的代码。
  此题的另外一个启发是,如果想对一个组合问题(多叉树)进行耗时优化,一种优化思路就是early stop。体现在代码上就是给递归出加上条件语句,如果条件语句不满足,就不会向更深处延伸,从而early stop.

if(open < max){
    cases(pref + "(", res, open + 1, close, max, left - 1); 
}
if(close < open){
    cases(pref + ")", res, open, close + 1, max, left - 1);
}

  这边还想提到的一点就是,官方的代码是先append, 再删除貌似没有我这样写简洁?

if (open < max) {
    cur.append("(");
    backtrack(ans, cur, open+1, close, max);
    cur.deleteCharAt(cur.length() - 1);
}
if (close < open) {
    cur.append(")");
    backtrack(ans, cur, open, close+1, max);
    cur.deleteCharAt(cur.length() - 1);
}

你可能感兴趣的:(数据结构,leetcode,算法,面试,组合,early,stop)