编程之美之买票找零

题目:假设有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;
    }
};

参考文献:

从《编程之美》买票找零问题说起,娓娓道来卡特兰数——兼爬坑指南

编程之美之买票找零,布布扣,bubuko.com

时间: 2024-12-14 18:51:24

编程之美之买票找零的相关文章

java多线程编程(3)买票

1,买票非同步版本 http://www.cnblogs.com/anbylau2130/archive/2013/04/17/3025347.html很详细 1 public class 多线程2 { 2 3 /** 4 * @param args 5 */ 6 public static void main(String[] args) { 7 // TODO Auto-generated method stub 8 Runnable r=new mythread(); 9 Thread t

编程之美之买书问题

拿到这个问题,我的第一反应是用贪心算法,优先满足不同种类多的,这样打的折扣比价多.但是,看了书中的分析发现,* 我们设定的贪心策略实际上是有问题的, ie 在买 5 + 3 本的时候会出错. 看到这里,书上说可以利用改进的贪心算法,感觉如果换了相应的折扣数量,可能又会有不同的结果了.因而,没有深入的研究下去. 既然,贪心算法不可行,那就用动态规划呗. 这里的动态规划思路很简单不过写起来有些复杂.我们这里用到了5维数组, 光是init 就写了好多. 其实我在写的时候,就在想有什么简单一点的方法可以

编程之美 1.5快速找出故障机器

题目: 有很多服务器存储数据,假设一个机器仅存储一个标号为ID的记录,假设机器总量在10亿以下且ID是小于10亿的整数,假设每份数据保存两个备份,这样就有两个机器存储了同样的数据. 问题是:1.假设在某个时间得到一个数据文件ID的列表,是否能快速地找出表中仅出现一次的ID?即快速找出出现故障的机器存储的数据ID. 2.如果有两台机器出现故障呢?(假设存储同一份数据的两台机器不会同时出现故障,即列表中缺少的是两个不等的ID) 给出了4种解法思路 解法一: 最传统的比较列表,需要遍历整个列表,记录每

【编程之美】2.8 找符合条件的整数

给定一个正整数N,求一个最小的正整数M(M > 1),使得N * M的十进制表示中只有0和1. 我的思路: 从最低位到最高位找M,每次使得乘积的最后面多一位符合0.1的条件. 那么先找能够让末尾数字变成0的备选项 举例若N的个位数是9  考虑从后面来的进位 c 让 x * 9 + c 的末尾是0或1 设个位数字为9 则eligibleNum中存储的数字eligibleNum[0][0] = 0 因为9 * 0 + 0 = 0 末尾符合0或1 eligibleNum[0][0] = 9 因为9 *

编程之美学习之快速找出故障机器

这种问题以及方法很常见.主要是思路要开阔,讲已知的问题抽象成数学模型或者函数表达式,这正是数学建模的真谛,problem solving(解决实际问题的能力). 法一:利用计数排序,用数组记下每个ID出现的次数,然后找出出现一次的那个ID,时空复杂度都是O(N).现在如果数据量很大,那么这样的空间复杂度是无法被容忍的 法二:利用两个相同的数异或结果为0,将所有的ID都异或一遍,显然最后剩下的值,即为出现次数为1次的那个数. 法三:如果存在两个数据出现一次的情况,还是利用异或,只是得将这两个出现一

【编程之美】目录

第1章  游戏之乐——游戏中碰到的题目 1.1 让CPU占用率听你的指挥 1.2 中国象棋将帅问题 1.3 一摞烙饼的排序 1.4 买书问题 第2章  数字之魅——数字中的技巧 2.1 求二进制中1的个数 2.2 不要被阶乘吓倒 2.3 寻找发帖"水王" 2.4 1的数目 2.5 寻找最大的K个数 2.6 精确表达浮点数 2.7 最大公约数问题 2.8 找符合条件的整数 2.9 斐波那契(Fibonacci)数列 2.10 寻找数组中的最大值和最小值 2.11 寻找最近点对 2.12

[BOP][Beauty of Programming][MSRA] 从“买票问题”谈起

问题(买票问题): 在一场激烈的足球赛开始前,售票工作正在紧张地进行中. 已知: 1.每张球票为50元. 2.现在有2n个人排队购票, 其中有n个人手持50元钞票,另外n个人手持100元钞票, 假设开始售票时,售票处没有零钱. 问:这2n个人有多少种排队方式,不至使售票处出现找不开钱的局面? 摘要: 通过对买票找零问题的分析,迁移到括号匹配问题,得到递推式.并通过数学分析中级数幂级数知识,推导出递推式的通项,以此解决部分衍生问题. 这里符号怎么玩…… 见外链吧 http://yunpan.cn/

调查:近7成受访网友买票还找黄牛

过年了,很多在外工作了一年的人们,随着乡愁的召唤,又开始了一年一度的大迁徙.南都联合大粤网发起的网络民调,有1141名网友参与调查.数据显示,今年春运,81.68%的返乡旅客依然选择乘坐火车.可是回家的路并不轻松,截至1月15日,依然还有89 .92%的人没有买到回家的火车票.与之对应的是,今年春运铁路12306网站首次施行提前60天购票,除夕从广州向全国各方向的火车票一经发售,就被抢购一空.如何才能买到回家的车票?数据给出的结论是,67.75%的受访网友是通过找黄牛才买到票的. 调查结果显示,

《编程之美》3.6判断链表是否相交之扩展:链表找环方法证明

先看看原题:<编程之美>3.6编程判断两个链表是否相交,原题假设两个链表不带环. 为了防止剧透使得没看过原题目的读者丧失思考的乐趣,我把最好的解法隐藏起来.由于这个问题本身的解答并不是本文的重点,扩展问题也采用这种形式呈现. 注:位于(*)符号之间的文字出自于:http://blog.csdn.net/v_july_v/article/details/6447013,作者v_JULY_v. 用指针p1.p2分别指向两个链表头,不断后移:最后到达各自表尾时,若p1==p2,那么两个链表必相交 用