算法学习之递归(个人学习)

文章介绍了递归的基本概念,通过实例解析了如何解决巴啦啦能量、求最大公约数和全排列等问题,展示了递归在处理整数分解中的应用,以及对应的C++代码实现。
摘要由CSDN通过智能技术生成

一、递归的概念

直接或间接的调用自身的算法叫递归算法。用函数自身给出定义的函数称为递归函数。

运用递归的比较简单的例子有:阶乘函数,Fibonacci函数等

递归的主要解题思路:

1、明确函数作用

2、寻找递归结束条件

3、找函数的等价关系

为了进一步理解递归的含义,从以下几个题进行介绍:

二、具体例题:

难度:简单

题目来源:牛客na

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

题目描述一:

给你一个数,让他进行巴啦啦能量,沙鲁沙鲁,小魔仙大变身,如果进行变身的数不满足条件的话,就继续让他变身。。。直到满足条件为止。

巴啦啦能量,沙鲁沙鲁,小魔仙大变身:对于一个数,把他所有位上的数字进行加和,得到新的数。

如果这个数字是个位数的话,那么他就满足条件。

输入描述:

给一个整数数字n(1<=n<=1e9)。

输出描述:

输出由n经过操作满足条件的数

示例1

输入

 12

12

输出

  3

3

说明

12 -> 1 + 2 = 3 

解析:本题需要用到%和/这种算术运算符和递归

1、分析题目:

如12->1+2=3 (个位数则不继续分解,需要进行返回)

如231->23+1->24->2+4->6(个位数不继续分解)

   231->2+3+1->6(个位数不进行分解)  这个231的分解分别对应着两种解法:

第一种解法:当然,如果没有发现这种规律可以使用第二种解法

#include<stdio.h>
int add(int n)
{
    if(n/10==0)
    {
        return n;
    }
    else{
        return add(n%10+n/10);
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    printf("%d",add(n));
     
}

第二种解法:设置了x来储存,给出例子进行验证会比较好理解,如132:

首先,我们需要通过while循环取到一个数的每一位并进行相加

进入while循环第一次:x=2;n=13;  第二次:x=3+2=5; n=1; 第三次:x=5+1=6;n=0

其次,进行递归,若是一个数则返回n,若不是,继续while把每一位进行相加

递归:add(6):判断是不是一个数,其实这里可以直接写if(n<10)来判断,有时候突然没想到哈哈哈

#include<stdio.h>
int add(int n)
{
    int x=0;
    if(n/10==0)
    {
        return n;
    }
    while(n){
        x=x+n%10;
        n=n/10;
     
    }
     return add(x);
  
}
int main()
{
    int n;
    scanf("%d",&n);
    printf("%d",add(n));
    
}

题目描述二

利用更相减损术求两个整数的最大公约数,即每次将较大的数变成大数减去小数的值

输入描述:

输入两个正整数,范围在1000000以内

输出描述:

输出一个整数

示例1

输入

4 6

4 6

输出

2

2

解析:本题用到递归,更相减损失数,这也是一种计算最大公约数的方法呢

分析题目:首先一定要分析这个题目的实现,是怎么得到这个结果的,可以在纸上演算一遍

据分析:更相减损失数:是不断的更新较大值,怎么更新呢,是通过不断的较大值-较小值的结果更新

举个例子说明(递归的理解):4 6  首先6>4,则更新6为6-4=2,所以这个例子变为了 4 2;

                                其次4>2,则更新4为4-2=2,所以这个例子变为了 2 2;

当最后更新出来的两个数字相等时,得到了这个最大公约数。

#include<stdio.h>
int cha(int a,int b)
{
    if(a==b)
    {
    return a;
    }
    else{
        if(a>b)
        {
            return cha(a-b,b);
        }
        else{
            return cha(a,b-a);
        }
        
    }
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d",cha(a,b));
    return 0;
    


}

题目描述三

小q最近迷上了各种好玩的数列,这天,他发现了一个有趣的数列,其递推公式如下:

f[0]=0 f[1]=1;
f[i]=f[i/2]+f[i%2];(i>=2)

现在,他想考考你,问:给你一个n,代表数列的第n项,你能不能马上说出f[n]的值是多少,以及f[n]所代表的值第一次出现在数列的哪一项中?(这里的意思是:可以发现这个数列里某几项的值是可能相等的,则存在这样一个关系f[n'] = f[n] = f[x/2]+f[x%2] = f[x]...(n'<n<x) 他们的值都相等,这里需要你输出最小的那个n'的值)(n<10^18)

输入描述:

输入第一行一个t
随后t行,每行一个数n,代表你需要求数列的第n项,和相应的n'
(t<4*10^5)

输出描述:

输出每行两个正整数
f[n]和n',以空格分隔

示例1

输入

2
0
1

输出

0 0
1 1

解析:本题用到递归

分析题目:该题一定要看懂 题目(呜呜呜,刚开始一直没看懂这个题目)经过演算,我发现

f(1)=1    2^1-1                   

f(4)=1    2^1-1

f(8)=1    2^1-1

这个题目就是要找到相同结果的最小的那个x 和它的值 显然这个例子是1 

#include<stdio.h>
#include<math.h>
long int di(long int n)
{
    if(n==0)
    {
        return 0;
    }
    else if(n==1)
    {
        return 1;
    }
    else{
        return di(n/2)+di(n%2);
    }
}
int main()
{
   long int a;
    scanf("%ld",&a);
    long int b;
    long int i;
    for(i=0;i<a;i++)
    {
        scanf("%ld",&b);
        long int t;
        long int m;
        t=di(b);
        m=pow(2,t)-1;
        printf("%ld %ld\n",t,m);
        
    }
    return 0;

}

难度:适中

全排列问题:

从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。

现有一例子:arr[1,2,3] 给出全排列的所有组合

核心算法:Swap是需要自己写的交换函数


void Perm(int* br, int k, int m)
{
	if (k == m)
	{
		for (int i = 0; i <= m; ++i)
		{
			printf("%d ", br[i]);
		}
		printf("\n");
	}
	else
	{
		for (int j = k; j <= m; ++j)
		{
			Swap(br[j], br[k]);
			Perm(br, k + 1, m);
			Swap(br[j], br[k]);
		}
	}
}
 

分析问题:k是第一个元素的坐标,m是指向最后一个元素的坐标,个人刚开始不理解,建议可以动笔画画,或者单步调试。理解是怎么递归的。

算法 | 全排列问题(图文详解)-CSDN博客 可见这个博主的文章,个人觉得讲得很清楚。

整数划分问题:

题目描述

整数划分就是将一个正整数表示成一系列正整数之和,问有多少种不同划分方案!  例如整数6可以划分成已下11种方案:
        6
        5 + 1
        4 + 2

        4 + 1 + 1
        3 + 3

        3 + 2 + 1

        3 + 1 + 1 + 1
        2 + 2 + 2

        2 + 2 + 1 + 1

        2 + 1 + 1 + 1 + 1
        1 + 1 + 1 + 1 + 1 + 1 

输入正整数n,计算n有多少种不同划分方案。

输入

包括多组数据,每组1个整数n。

输出

n的不同划分方案种数。

样例输入 Copy
1
2
3
4
5
6
样例输出 Copy
1
2
3
5
7
11

分析问题:

该题目是将n划分为一系列整数和,在n的所有划分中,将最大加数n,不大于m的划分个数记为q(n,m):

当m=1 或者n=1时,划分只有一种可能性,即为1 1 1 1 1 1 1很多个1.

当n<m时,应变为q(n,n);  

当n=m时,1+q(n,n-1)  

当n>m>1时,q(n,m-1)+q(n-m,m)

具体代码:

#include<stdio.h>
int divide(int n,int m)
{
    if(m==1)
    {
        return 1;
    }
    if(n<m)
    {
        return divide(n,n);
    }
    if(n==m)
    {
        return 1+divide(n,n-1);
    }
    if(n>m&&n>1&&m>1)
    {
        return divide(n,m-1)+divide(n-m,m);
    }
     
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
    int p=0;
    p=divide(n,n);
    printf("%d\n",p);
     
    }
     
     
}

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值