zoukankan      html  css  js  c++  java
  • 22.括号生成

    数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且有效的括号组合。

    示例:

    输入:n = 3
    输出:[
           "((()))",
           "(()())",
           "(())()",
           "()(())",
           "()()()"
         ]
    

    解法一

    又臭又长,还超时。

     vector<string> ans;
        string brackets;
        map<string,int> m;
        bool isValid(string s){
            stack<char> st;
            if(s[0]==')') return false;
            st.push('(');
            for(int i=1;i<s.size();++i){
                //访问栈顶元素要先检查栈不空,之前没有检查导致好久才看出错误。
                if(s[i]==')'&&st.size()!=0&&st.top()=='(') {
                    st.pop();
                }
                else if(s[i]==')') return false;
                else st.push('(');
            }
            return true;
        }
        void backtrack(int t,int n,string cur){
            if(t>=2*n) {
                if(m[cur]==0)
                    ans.push_back(cur);
                m[cur]++;
                return;
            }
            for(int i=t;i<2*n;++i){
                swap(cur[i],cur[t]);
                if(!isValid(cur.substr(0,t+1))) return;
                else{
                backtrack(t+1,n,cur);
                swap(cur[i],cur[t]);
                }
            }
        }
        vector<string> generateParenthesis(int n) {
            for(int i=0;i<n;++i) brackets+="()";
            backtrack(0,n,brackets);
            return ans;
        }
    

    花了好久才看出越界访问的原因,原来是访问栈顶元素前没有检查它是否为空:

    分析:

    这里是用排列树的思想,但实际上只有左括号和右括号两种符号,因此不仅时间复杂度大而且会产生重复结果。
    

    解法二

    使用双递归的方法:

     vector<string> ans;
        void backtrack(int left,int right,string cur){
            if(left==0&&right==0) {
                ans.push_back(cur);
                return;
            }
            //替换下面两行顺序,即先遍历右子树再遍历左子树也是可以的。
            if(left>0) backtrack(left-1,right,cur+'(');
            //只有当剩余')'比'('多时才能添加')'。
            if(right>left) backtrack(left,right-1,cur+')');
        }
        vector<string> generateParenthesis(int n) {
            backtrack(n,n,"");
            return ans;
        }
    

    tips:

    只有在剩余的右括号不少于左括号时才有可能符合要求。
    **遇到这种每次只有两种选择的问题可以使用双递归(二叉树遍历)方法。**
    因为用二叉树的思想,不同路径对应不同结果,因此不会有重复结果。
    

    分析:

    只有左括号和右括号两种选择,可以考虑双递归也即用二叉树的思想。这种算法实际上就是二叉树的先序遍历。当还剩左括号时遍历左子树(加左括号);当剩余右括号多于左括号时遍历右子树(加右括号)。要注意的是只有在剩余右括号多于左括号时才能加右括号,否则得到的结果必然不符要求。
    

    解法三

    也是使用双递归的方法,是对解法一的改进。

     vector<string> ans;
        bool isValid(const string& s){
            stack<char> st;
            if(s[0]==')') return false;
            st.push('(');
            for(int i=1;i<s.size();++i){
                //访问栈顶元素要先检查栈不空,之前没有检查导致好久才看出错误。
                if(s[i]==')'&&st.size()!=0&&st.top()=='(') {
                    st.pop();
                }
                else if(s[i]==')') return false;
                else st.push('(');
            }
            return true;
        }
        void backtrack(int left,int right,string cur){
            if(left==0&&right==0) {
                if(isValid(cur))
                    ans.push_back(cur);
                return;
            }
            //没有检查当前生成字符串的合法性,而是把检查过程放到了最后。
            if(left>0) backtrack(left-1,right,cur+'(');
            if(right>0) backtrack(left,right-1,cur+')');
        }
        vector<string> generateParenthesis(int n) {
            backtrack(n,n,"");
            return ans;
        }
    
  • 相关阅读:
    Window 窗口类
    使用 Bolt 实现 GridView 表格控件
    lua的table库
    Windows编程总结之 DLL
    lua 打印 table 拷贝table
    使用 xlue 实现简单 listbox 控件
    使用 xlue 实现 tips
    extern “C”
    COleVariant如何转换为int double string cstring
    原来WIN32 API也有GetOpenFileName函数
  • 原文地址:https://www.cnblogs.com/Frank-Hong/p/13302333.html
Copyright © 2011-2022 走看看