程式設計之美之買票找零

fangjian1204發表於2014-08-13

題目:假設有2N個人在排隊買票,其中有N個人手持50元的鈔票,另外有N個人手持100元的鈔票,假設開始售票時,售票處沒有零錢,問這2N個人有多少種排隊方式,不至使售票處出現找不開錢的局面?

分析:隊伍的序號標為0,1,...,2n-1,並把50元看作左括號,100元看作右括號,合法序列即括號能完成配對的序列。對於一個合法的序列,第0個一定是左括號,它必然與某個右括號配對,記其位置為k。那麼從1到k-1、k+1到2n-1也分別是兩個合法序列。那麼,k必然是奇數(1到k-1一共有偶數個),設k=2i+1。那麼剩餘括號的合法序列數為f(2i)*f(2n-2i-2)個。取i=0到n-1累加,並且令f(0)=1,則f(2n) =  ∑f(2i)*f(2n-2i-2),其中i = 0 ... n-1,最後的結果即為卡特蘭數

我們們看leetcode上面有一個類似的問題,即

Generate Parentheses

 

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

For example, given n = 3, a solution set is:

"((()))", "(()())", "(())()", "()(())", "()()()"

該問題買票找零問題一樣,通過買票找零問題我們可以知道,針對一個長度為2n的合法排列,第1到2n個位置都滿足如下規則:左括號的個數大於等於右括號的個數。所以,我們就可以遞迴處理:如果左括號個數大於0,則我們可以直接列印左括號;如果左括號大於右括號且右括號大於0,則可以列印右括號。

class Solution {
public:
    void generateParenthesis(int left,int right,string parenthese,vector<string>& res)
    {
    	if(left == 0 && right == 0)//得到一個結果
    	{
    		res.push_back(parenthese);
    		return;
    	}
    	if(left > 0)generateParenthesis(left - 1,right,parenthese + '(',res);
    	if(right > 0 && left < right)generateParenthesis(left,right-1,parenthese+')',res);
    }
    vector<string> generateParenthesis(int n) 
    {
    	vector<string> res;
    	if(n <= 0)return res;
    	generateParenthesis(n,n,"",res);
    	return res;
    }
};

再看leetcode上的關於唯一二叉樹個數的問題,也是程式設計之美中買票找零的擴充套件問題:

Unique Binary Search Trees

 

Given n, how many structurally unique BST's (binary search trees) that store values 1...n?

For example,
Given n = 3, there are a total of 5 unique BST's.

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

class Solution {
public:
    int numTrees(int n) {
    	vector<int> num(n+1,0);
    	if(n <= 0)return 0;
    	num[0] = 1;
    	num[1] = 1;
    	int i,left,right;
    	for(i = 2; i <= n; ++i)//節點總數
    	{
    		for(left = 0; left < i; ++left)
    		{
    			right = i - left - 1;
    			num[i] += num[left] * num[right];//左子樹的個數 * 右子樹的個數
    		}
    	}
    	return num[n];
    }
};

Unique Binary Search Trees II

 

Given n, generate all structurally unique BST's (binary search trees) that store values 1...n.

For example,
Given n = 3, your program should return all 5 unique BST's shown below.

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.

思路和上面的一樣,選取一個根節點,然後遞迴左右子樹,以該根節點為結果的數的個數是左右子樹的乘積,所以是一個二重迴圈

class Solution {
public:
    vector<TreeNode *> generateTrees(int start,int end) {
    	vector<TreeNode*> res;
    	if(start > end)//空子樹
    	{
    		res.push_back(NULL);
    		return res;
    	}
    	int k;
    	for(k = start; k <= end; ++k)//根節點的位置
    	{
    		vector<TreeNode*> left  = generateTrees(start,k-1);
    		vector<TreeNode*> right = generateTrees(k+1,end);
    		int i,j;
    		for(i = 0; i < left.size();++i)
    		{
    			for(j = 0; j < right.size();++j)
    			{
    				TreeNode* root = new TreeNode(k);//所有以該根節點為結果的樹
    				root -> left = left[i];
    				root -> right = right[j];
    				res.push_back(root);
    			}
    		}
    	}
    	return res;
    }
    vector<TreeNode *> generateTrees(int n) {
    	vector<TreeNode*> res;
    	res = generateTrees(1,n);
    	return res;
    }
};

參考文獻:

http://blog.csdn.net/han_xiaoyang/article/details/11938973

從《程式設計之美》買票找零問題說起,娓娓道來卡特蘭數——兼爬坑指南

相關文章