五大经典算法一 递归与分治
2017-03-21 12:06
323 查看
我们要讲到分治算法,我觉得有必要说一下递归,他们就像一对孪生兄弟,经常同时应用在算法设计中,并由此产生许多高效的算法。
递归算法:直接或者间接不断反复调用自身来达到解决问题的方法。要求原始问题可以分解为相同问题的子问题。、
需要:
1 递归边界 2 自身调用
特点分析:
递归思路简单清晰,如果分析出将很快得到结果;递归将多次调用,使用到堆栈,算法效率低,费时费内存。
常用场景:阶乘,斐波纳契数列、汉诺塔问题,整数划分,枚举排列及二叉树,图的搜索相关问题。
例题1 Hanoi问题
有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至B杆:每次只能移动一个圆盘;大盘不能叠在小盘上面。问:如何移?最少要移动多少次?
设hanoi(n,x,y,z)表示将n个圆盘从x通过y移动到z上则有递归模型:
hanoi:move(n,x,z) when n==1
hanoi:hanoi(n-1,x,z,y);move(1,x,z);hanoi(n-1,y,x,z) when n>1
第1个盘,从a移动到b
第2个盘,从a移动到c
第1个盘,从b移动到c
第3个盘,从a移动到b
第1个盘,从c移动到a
第2个盘,从c移动到b
第1个盘,从a移动到b
例题2 整数划分问题
整数划分问题是算法中的一个经典命题之一,有关这个问题的讲述在讲解到递归时基本都将涉及。所谓整数划分,是指把一个正整数n写成如下形式:
n=m1+m2+...+mi,其中1<=mi<=n,则称{m1,m2,...,mi}为n的一个划分。如果{m1,m2,..,mi}最大值不超过m,即max(m1,m2,...,mi)<=m,则称它属于n的一个m划分。这里我们记n的m划分的个数为f(n,m)。例如n=4时,有4},{3,1},{2,2},{2,1,1},{1,1,1,1}这样的5个划分则f(n,4)=5。下面将用递归法求f(n,m):
a)当n==1时,不论m何值,都只有一种划分{1};
b)当m==1时,不论n何值,都只有一种划分{1,1,...,1};
c)当n==m时,
分划分中包含n时只有一种;
当划分中不包含n即最大值小于m时有f(n,m-1)种;
故f(n,n)=1+f(n,n-1);
d)当n<m时,类似f(n,n)
e)当n>m,这是最一般情况,
若划分中包含m,即{{x1,x2,...,xi},m},x1+x2+...+xi=n-m,则f(n,m)=f(n-m,m);
若划分中不包含m,即划分中值都比m小,f(n,m)=f(n,m-1)
故总数 f(n, m) = f(n-m, m)+f(n,m-1)
则递归模型:
f(n,m)=1 when n==1 or m==01
f(n,m)=f(n,n) when m>n
f(n,m)=1+f(n,m-1) when m==n
f(n,m)=f(n-m,m)+f(n,m-1) when m<n
输出一个数的枚举排列或者一个序列的全排列,递归生成是一种很方便的做法。
先说枚举排列,输入一个整数n,按照大小输出1~n的所有排列如n=3时所有·排列结果:123,132,213,231,312,321
先输出以1开头的排列
再输出以2开头的排列
。。。
最后输出以n开头的排列
故这需要一个1-n的循环即可,循环内部就是一个排列生成过程。
以i开头的排列的特点是,第一位是i,后面是(1,2,...,i-1,i+1,..,n)的排列,按照定义(1,2,...,i-1,i+1,..,n)也必须按照大小顺序排列,故可以采用递归。设递归函数为permutation(int a[],int
n,int cur),其递归模型:
输出已排好序列a when n==cur,cur为当前需要确定的元素位置
for 从小到达每个元素v
permutation(a+v,n,cur+1)
具体分析:
当第一次进入循环时,i=1,最后输出以1开始的两个序列123 132
上述排列程序只使用任意两个元素均不相同的序列,若有一个序列P,并且P中含有相同的元素,则根据上面程序进行修改
由于数组P可能有重复元素故需要注意两点:
1 为避免排列序列重复,首元素应避免一样;
2 非首元素重复允许
216题也类似:
Find all possible combinations of k numbers that add up to a number
n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
Example 1:
Input: k = 3, n = 7
Output:
Example 2:
Input: k = 3, n = 9
Output:
例题4 二叉树或者图的问题
这一类问题基本上是递归最常用的场景,在分析树或者图时已经应用很多不再赘述。
下面再讲分治法
递归算法:直接或者间接不断反复调用自身来达到解决问题的方法。要求原始问题可以分解为相同问题的子问题。、
需要:
1 递归边界 2 自身调用
特点分析:
递归思路简单清晰,如果分析出将很快得到结果;递归将多次调用,使用到堆栈,算法效率低,费时费内存。
常用场景:阶乘,斐波纳契数列、汉诺塔问题,整数划分,枚举排列及二叉树,图的搜索相关问题。
例题1 Hanoi问题
有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至B杆:每次只能移动一个圆盘;大盘不能叠在小盘上面。问:如何移?最少要移动多少次?
设hanoi(n,x,y,z)表示将n个圆盘从x通过y移动到z上则有递归模型:
hanoi:move(n,x,z) when n==1
hanoi:hanoi(n-1,x,z,y);move(1,x,z);hanoi(n-1,y,x,z) when n>1
void move(int no,char s,char d) {cout<<"第"<<no<<"个盘,从"<<s<<"移动到"<<d<<endl; } void hanoi(int n,char x,char y,char z){ if(n==1)move(n,x,z); else { hanoi(n-1,x,z,y); move(n,x,z); hanoi(n-1,y,x,z); } }验证hanoi(3,'a','c','b'):
第1个盘,从a移动到b
第2个盘,从a移动到c
第1个盘,从b移动到c
第3个盘,从a移动到b
第1个盘,从c移动到a
第2个盘,从c移动到b
第1个盘,从a移动到b
例题2 整数划分问题
整数划分问题是算法中的一个经典命题之一,有关这个问题的讲述在讲解到递归时基本都将涉及。所谓整数划分,是指把一个正整数n写成如下形式:
n=m1+m2+...+mi,其中1<=mi<=n,则称{m1,m2,...,mi}为n的一个划分。如果{m1,m2,..,mi}最大值不超过m,即max(m1,m2,...,mi)<=m,则称它属于n的一个m划分。这里我们记n的m划分的个数为f(n,m)。例如n=4时,有4},{3,1},{2,2},{2,1,1},{1,1,1,1}这样的5个划分则f(n,4)=5。下面将用递归法求f(n,m):
a)当n==1时,不论m何值,都只有一种划分{1};
b)当m==1时,不论n何值,都只有一种划分{1,1,...,1};
c)当n==m时,
分划分中包含n时只有一种;
当划分中不包含n即最大值小于m时有f(n,m-1)种;
故f(n,n)=1+f(n,n-1);
d)当n<m时,类似f(n,n)
e)当n>m,这是最一般情况,
若划分中包含m,即{{x1,x2,...,xi},m},x1+x2+...+xi=n-m,则f(n,m)=f(n-m,m);
若划分中不包含m,即划分中值都比m小,f(n,m)=f(n,m-1)
故总数 f(n, m) = f(n-m, m)+f(n,m-1)
则递归模型:
f(n,m)=1 when n==1 or m==01
f(n,m)=f(n,n) when m>n
f(n,m)=1+f(n,m-1) when m==n
f(n,m)=f(n-m,m)+f(n,m-1) when m<n
int splitint(int n,int m){ if(n==1||m==1)return 1; if(n<m)return splitint(n,n); else if(n==m)return (1+splitint(n,m-1)); else return(splitint(n-m,m)+splitint(n,m-1)); }例题3 枚举排列问题
输出一个数的枚举排列或者一个序列的全排列,递归生成是一种很方便的做法。
先说枚举排列,输入一个整数n,按照大小输出1~n的所有排列如n=3时所有·排列结果:123,132,213,231,312,321
先输出以1开头的排列
再输出以2开头的排列
。。。
最后输出以n开头的排列
故这需要一个1-n的循环即可,循环内部就是一个排列生成过程。
以i开头的排列的特点是,第一位是i,后面是(1,2,...,i-1,i+1,..,n)的排列,按照定义(1,2,...,i-1,i+1,..,n)也必须按照大小顺序排列,故可以采用递归。设递归函数为permutation(int a[],int
n,int cur),其递归模型:
输出已排好序列a when n==cur,cur为当前需要确定的元素位置
for 从小到达每个元素v
permutation(a+v,n,cur+1)
void permutation(int a[],int n,int current){ if(current==n){ for(int i=0;i<n;i++)cout<<a[i]<<" ";cout<<endl; } else { for(int i=1;i<=n;i++) {int f=0; for(int j=0;j<current;j++) if(a[j]==i)f=1;//a[0]-a[current-1]是已经排好的 if(f==0){a[current]=i;permutation(a,n,current+1);} } } }
具体分析:
当第一次进入循环时,i=1,最后输出以1开始的两个序列123 132
上述排列程序只使用任意两个元素均不相同的序列,若有一个序列P,并且P中含有相同的元素,则根据上面程序进行修改
由于数组P可能有重复元素故需要注意两点:
1 为避免排列序列重复,首元素应避免一样;
2 非首元素重复允许
void permutation1(int a[],int n,int p[],int current){ if(current==n) {for(int i=0;i<n;i++)cout<<a[i]<<" ";cout<<endl; } else { for(int i=0;i<n;i++) if(!i||p[i]!=p[i-1])//防止重复 { int f=0;int num=0; for(int j=0;j<n;j++)if(p[i]==p[j])num++; for(int j=0;j<current;j++) if(a[j]==p[i])f++;; if(f<num){a[current]=p[i];permutation1(a,n,p,current+1);} } } }
216题也类似:
Find all possible combinations of k numbers that add up to a number
n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
Example 1:
Input: k = 3, n = 7
Output:
[[1,2,4]]
Example 2:
Input: k = 3, n = 9
Output:
[[1,2,6], [1,3,5], [2,3,4]]
class Solution { public: void helper_combination13(int k,int start,int target,vector<int>&item,vector< vector<int> >&res){ if(target<0||(target!=0&&item.size()==k))return; if(item.size()==k&&target==0){res.push_back(item);return;} for(int i=start;i<10;i++) { item.push_back(i); helper_combination13(k,i+1,target-i,item,res); item.pop_back(); } } vector<vector<int> > combinationSum3(int k,int n){ vector< vector<int> >res; vector<int> item; helper_combination13(k,1,n,item,res); return res; } };
例题4 二叉树或者图的问题
这一类问题基本上是递归最常用的场景,在分析树或者图时已经应用很多不再赘述。
下面再讲分治法
相关文章推荐
- 【从零学习经典算法系列】分治与递归1——递归表达式与解法初步
- 五大经典算法之三动态递归DP
- 五大基础算法(枚举、递归、分治、贪心、模拟)
- 【从零学习经典算法系列】分治与递归2——主方法
- 五大常用经典算法(分治、动态规划、贪心、回溯、分支限界)
- 和菜鸟一起学算法之递归和分治简单实例
- java经典算法_016猴子吃桃问题(递归)
- 算法系列15天速成——第五天 五大经典查找【中】
- 算法系列15天速成——第六天 五大经典查找【下】
- 算法系列15天速成——第六天 五大经典查找【下】
- 递归和分治思想2 - 数据结构和算法32
- 和菜鸟一起学算法之递归和分治简单实例
- 算法系列15天速成——第五天 五大经典查找【中】
- 递归和分治思想3|汉诺塔 - 数据结构和算法33
- 递归和分治思想1 - 数据结构和算法31
- 递归和分治思想1 - 数据结构和算法31
- java经典算法_021利用递归方法求5!
- 算法系列15天速成——第四天 五大经典查找【上】
- 算法系列15天速成——第四天 五大经典查找【上】
- 【算法复习二】传统基本算法(迭代、递归、分治)