参考 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对括号的全部合法排列。编程

解答:数组

该问题解的个数就是卡特兰数,可是如今不是求个数,而是要将全部合法的括号排列打印出来。post

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


按照这种思路,代码以下:spa

 

[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. }  

 

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

 

做为一个例子,看一下数组的入栈出栈顺序问题:给定一个长度为n的不重复数组,求全部可能的入栈出栈顺序。该问题解的个数也是卡特兰数,根据上面的思路,咱们也能够写出一个相似的代码:code

[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只能在头部删除元素,因此没有采用。
相关文章
相关标签/搜索