zoukankan      html  css  js  c++  java
  • 参考 generate-parentheses

    分析:
    关键:当前位置左括号不少于右括号
    图是什么?
           节点:目前位置左括号和右括号数(x,y)(x>=y)
           边:从(x,y)到(x+1,y)和(x,y+1)
           x==y时,没有(x,y+1)这条边
    解是什么?
            从(0,0)出发到(n,n)的全部路径
     
    import java.util.ArrayList;
     
    public class Solution {
        public void help(int n, int x, int y, String s, ArrayList<String> list)
        {
            // 终止条件
        if(y==n)
            {
                list.add(s);
            }
            if(x<n)
            {
                help(n,x+1,y,s+"(",list);
            }
            // 递归过程中 左括号x的个数必须大于等于右括号个数
            if(x>y)
            {
                help(n,x,y+1,s+")",list);
            }
        }
        
        public ArrayList<String> generateParenthesis(int n) {
        ArrayList<String> list = new ArrayList<String>();
            help(n,0,0,"",list);
            return list;
        }
    }
     
    ===

    leetcode之 Generate Parentheses

    标签: leetcode生成括号卡特兰数
     分类:

    题目:http://oj.leetcode.com/problems/generate-parentheses/

    描述:给定一个非负整数n,生成n对括号的所有合法排列。

    解答:

    该问题解的个数就是卡特兰数,但是现在不是求个数,而是要将所有合法的括号排列打印出来。

           该问题和《编程之美》的买票找零问题一样,通过买票找零问题我们可以知道,针对一个长度为2n的合法排列,第1到2n个位置都满足如下规则:左括号的个数大于等于右括号的个数。所以,我们就可以按照这个规则去打印括号:假设在位置k我们还剩余left个左括号和right个右括号,如果left>0,则我们可以直接打印左括号,而不违背规则。能否打印右括号,我们还必须验证left和right的值是否满足规则,如果left>=right,则我们不能打印右括号,因为打印会违背合法排列的规则,否则可以打印右括号。如果left和right均为零,则说明我们已经完成一个合法排列,可以将其打印出来。通过深搜,我们可以很快地解决问题,针对n=2,问题的解空间如下:


    按照这种思路,代码如下:

    [cpp] view plain copy
     
     print?
    1. void generate(int leftNum,int rightNum,string s,vector<string> &result)  
    2.     {  
    3.         if(leftNum==0&&rightNum==0)  
    4.         {  
    5.             result.push_back(s);  
    6.         }  
    7.         if(leftNum>0)  
    8.         {  
    9.             generate(leftNum-1,rightNum,s+'(',result);  
    10.         }  
    11.         if(rightNum>0&&leftNum<rightNum)  
    12.         {  
    13.             generate(leftNum,rightNum-1,s+')',result);  
    14.         }  
    15. }  

    网上对该问题的解答非常多,无一例外都采用了递归,但是鲜见和上面思路如此清晰的算法。上述算法的思路是很多问题的通解,值得仔细研究。

    作为一个例子,看一下数组的入栈出栈顺序问题:给定一个长度为n的不重复数组,求所有可能的入栈出栈顺序。该问题解的个数也是卡特兰数,根据上面的思路,我们也可以写出一个类似的代码:

    [cpp] view plain copy
     
     print?
    1. void inoutstack(int in,int out,deque<int> &q,stack<int> &s,deque<int> seq,vector<deque<int>> &result)  
    2.     {  
    3.         if(!in&&!out)  
    4.         {  
    5.             result.push_back(q);  
    6.             return;  
    7.         }  
    8.   
    9.         if(in>0)  
    10.         {  
    11.             s.push(seq.front());  
    12.             seq.pop_front();  
    13.             inoutstack(in-1,out,q,s,seq,result);  
    14.             seq.push_front(s.top());  
    15.             s.pop();  
    16.         }  
    17.   
    18.         if(out>0&&in<out)  
    19.         {  
    20.             q.push_back(s.top());  
    21.             s.pop();  
    22.             inoutstack(in,out-1,q,s,seq,result);  
    23.             s.push(q.back());  
    24.             q.pop_back();  
    25.         }  
    26.     }  
    上述代码由于采用了栈和队列模仿整个过程,所以显得略微复杂,但是代码的基本结构还是符合一个类似的基本规则:在某一个特定时刻,入栈的次数大于或者等于出栈的次数。在生成括号的问题中,我们利用一个string来保存结果,由于打印左括号时不影响打印右括号,所以无需复杂的状态恢复。在入栈出栈顺序问题中,由于两次递归调用共享同一个栈和队列,所以我们需要手动恢复其内容。在恢复时,队列会从头部删除和添加,所以我们采用了deque,它可以在头部添加和删除元素。queue只能在头部删除元素,所以没有采用。
     
  • 相关阅读:
    android常用的Application类
    Android一些问题的解决方案
    MakeFile相关
    Android源码与设计模式之notifyDataSetChanged()方法与观察者模式
    Activity启动模式与onNewIntent()简述
    (转)eval与迭代
    ADB命令
    其他常用工具类
    文件操作常用工具方法
    [TJOI2007] 可爱的质数
  • 原文地址:https://www.cnblogs.com/titer1/p/8137295.html
Copyright © 2011-2022 走看看