參考 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只能在頭部刪除元素,因此沒有采用。
相關文章
相關標籤/搜索