递归经典问题(1)-简单题

简单计算:

1.阶乘n!

int factorial(int n)
{
    if(n<=1) return n;
    return n*factorial(n-1);
}

阶乘(非递归方法):

int factorial(int n)
{
    int sum = 1;
    while(n>1){
        sum*=n;
        n--;
    }
}

计算累加和:计算1+2+3+…+n

int get_sum(int n)
{
    if(n==1) return 1;
    return n+get_sum(n-1);
}

2.斐波那契;

int fib(int n)
{
    if(n<=1) return n;
    return fib(n-1)+fib(n-2);
}

3.排列①:m个A和n个字母B能排列多少个组合?

int dfs(int m,int n)
{
    printf("m=%d,n=%d\n",m,n);
    if(m==0||n==0) return 1;
    return dfs(m-1,n)+dfs(m,n-1);
}

排列②:全排列

(1)C++STL全排列函数next_permutation()在使用前需要对欲排列数组按升序排序,否则只能找出该序列之后的全排列数;

此外,next_permutation(node,node+n,cmp)可以对结构体num按照自定义的排序方式cmp进行排序。

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int num[3]={1,2,3};
    do
    {
        cout<<num[0]<<" "<<num[1]<<" "<<num[2]<<endl;
    }while(next_permutation(num,num+3));
    return 0;
}
/*
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
*/

(2)手写递归:

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

const int N = 100;
int p[N];
bool vis[N];
int ans = 0;
int n;

void print()
{
    for(int i = 1; i <= n; i++){
        printf("%d ",p[i]);
    }
    printf("\n");
}

void dfs(int s)
{
    if(s==n+1){
        ans++;
        print();
        return;
    }
    for(int i = 1; i <= n; i++){
        if(!vis[i]){
            p[s] = i;
            vis[i] = true;
            dfs(s+1);
            vis[i] = false;
        }
    }
}


int main()
{
    printf("请输入一个小于100的正整数:");
    scanf("%d",&n);
    dfs(1);
    cout << ans;
	return 0;
}

4.n个球,任取m个不放回,问有多少种取法

int dfs(int n,int m)
{
    printf("%d,%d\n",n,m);
    if(n<m) return 0;
    if(n==m||m==0) return 1;//注意m=0时也有一种取法
    return dfs(n-1,m)+dfs(n-1,m-1);//该球不取,则继续从n-1个球中取m个;若取,则继续从n-1个球中取m-1个
}

5.反序输出

①字符串翻转

void rev(string s)
{
    if(s.size()>1){
        rev(s.substr(1,s.size()));
    }
    cout << s[0];
}

②整数倒序输出

void rev(int n)
{
    if(n==0) return;
    cout << n%10;
    rev(n/10);
}

6.爬楼梯:一步只能迈1或2个台阶,第一步迈左脚,然后左右交替,最后一步迈右脚。(即一共要走偶数步)

问有多少种走法?

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int ans = 0;

void dfs(int step,int flag)
{
    if(step==39&&flag%2==0){
        ans++;
        return;
    }
    if(step>39) return;
    dfs(step+1,flag+1);
    dfs(step+2,flag+1);
}

int main()
{
    dfs(0,0);//1,1开始是错误答案,因为第一步也可以迈两步
    cout << ans;
	return 0;
}

/*
ans=51167078
*/

或:

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int dfs(int step,int flag)
{
    if(step==0&&flag%2==0){
        return 1;
    }
    if(step<0) return 0;
    return dfs(step-1,flag+1)+dfs(step-2,flag+1);
}

int main()
{
    cout << dfs(39,0);//1,1开始是错误答案,因为第一步也可以迈两步
}

7.折半查找(二分查找)

int Find(int a[],int k,int low,int high)
{
	int i,mid;
	if(low>high)
		i=-1;
	else
	{
		mid=(low+high)/2;
		if(a[mid]==k)
			i=mid;
		else if(a[mid]<k)
			i=Find(a,k,mid+1,high);
		else
			i=Find(a,k,low,mid-1);
	}
	return i;
}

8.汉诺塔

void move(char X,char Y)
{
    printf("move:%c->%c\n",X,Y);
}

//将n个圆盘由A移到C,并且排列顺序不变(即由上至下为由小至大
void hanoi(int n,char A,char B,char C)
{
    if(n==1){
        move(A,C);
        return;
    }
    hanoi(n-1,A,C,B);//先将n-1个圆盘由A移动到B,借助C
    move(A,C);//再将第n个圆盘由A移动至C
    hanoi(n-1,B,A,C);//最后将n-1个圆盘由B移动到C,借助A;则完成了由A->C的移动
}

9.猴子吃桃

有一只猴子摘了一大堆桃子吃,它按照这样的规律吃桃子:第一天吃一半多一个,第二天吃第一天剩余的一半多一个,第三天吃第二天剩余的一半多一个…以此类推,当第七天时,恰好只剩下一个桃子。求猴子一共摘了多少个桃子?

n:表示第几天       F(n):表示第n天有多少个桃子

F(7) = 1

F(6) = ( F(7) + 1 ) * 2

F(5) = ( F(6) + 1 ) * 2

F(4) = ( F(5) + 1 ) * 2

F(n) = ( F(n+1) + 1 ) * 2

通过上面一系列的表达式,可以发现递归结构的两个关键信息

递归通项式:F(n)=(F(n+1) + 1) * 2

递归终止情况:F(7) = 1

int dfs(int n)
{
    if(n==7) return 1;
    return 2*(dfs(n+1)+1);
}

10.十进制转二进制输出:

//n为正整数
void dec2bin(int n)
{
    if(n==0) return;
    dec2bin(n/2);
    cout << n%2;
}

11.求组成一个正整数的所有数字之和

int get_sum(int n)
{
    if(n==0) return 0;
    return n%10+get_sum(n/10);
}

12.n^k递归实现

int power(int n,int k)
{
    if(n==0) return 0;
    if(k==0) return 1;
    if(k==1) return n;
    return n*power(n,k-1);
}

补充:整数的快速幂运算

13.求最大公约数(辗转相除法)

int gcd(int a,int b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}

14.求最小公倍数

①最小公倍数=两数乘积/最大公约数

int lcm(int a,int b)
{
    return a*b/gcd(a,b);
}

②穷举法

//需满足a<=b
int lcm(int a,int b)
{
    for(int i = b; ; i+=b){
        if(i%a==0) return i;
    }
}

15.回文串判断

bool judge(string s)
{
    if(s.size()==1||s.size()==0) return true;
    if(s[0]!=s[s.size()-1]) return false;
    return judge(s.substr(1,s.size()-2));
}

以上均为楼主自己测试写的代码,若有不完美之处,请大家指正!

    原文作者: 汉诺塔问题
    原文地址: https://blog.csdn.net/weixin_36313227/article/details/88699365
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞