当前位置: 首页 > news >正文

【蓝桥杯速成】| 4.递归

递归

 题目一:最大公约数

问题描述

1979. 找出数组的最大公约数 - 力扣(LeetCode)

给你一个整数数组 nums ,返回数组中最大数和最小数的 最大公约数 。

两个数的 最大公约数 是能够被两个数整除的最大正整数。

解题步骤

需要返回数组中最大最小值的最大公约数

那么首先需要求出最大最小值

可以使用for循环遍历得到

int minnum=INT_MAX,maxnum=INT_MIN;
for(int i=0;i<nums.size();i++){
    if(nums[i]<minnum){
        minnum=nums[i];
    }
    if(nums[i]>maxnum){
        maxnum=nums[i];
    }
}

当然也可以使用

求最大值和最小值的函数

  1. 最大值std::max_element

  2. 最小值std::min_element

这些函数返回的是指向最大值或最小值的迭代器,因此需要通过解引用操作符 * 来获取具体的值。

int maxnum=*max_element(nums.begin(),nums.end());
int minnum=*min_element(nums.begin(),nums.end());

 接下来就是求最大公约数

根据数学知识,我们可以使用辗转相除法

 那么很明显这是个递归过程,每次要求的是较大值除以较小值的余数,

终止条件就是余数为零,代表整除

所以求最大公倍数的函数应该是

int GCD(int maxnum,int minnum){
    if(maxnum%minnum == 0)
        return minnum;
    else 
        return GCD(minnum,maxnum%minnum);
}

 最后只需要在主函数中调用即可,完整代码在下面!

补充说明:C++的标准库中有计算两个整数最大公约数的函数,就叫gcd,可以直接调用,但此处想强调的是最基础的递归逻辑,故手动实现了一把!

code

class Solution {
public:
    int GCD(int maxnum,int minnum){
        if(maxnum%minnum == 0)
            return minnum;
        else 
            return GCD(minnum,maxnum%minnum);
    }
    int findGCD(vector<int>& nums) {
        // int minnum=INT_MAX,maxnum=INT_MIN;
        // for(int i=0;i<nums.size();i++){
        //     if(nums[i]<minnum){
        //         minnum=nums[i];
        //     }
        //     if(nums[i]>maxnum){
        //         maxnum=nums[i];
        //     }
        // }
        int maxnum=*max_element(nums.begin(),nums.end());
        int minnum=*min_element(nums.begin(),nums.end());
        return GCD(maxnum,minnum);
    }
};


题目二:FJ的字符串

问题描述

FJ在沙盘上写了这样一些字符串:
  A1 = “A”
  A2 = “ABA”
  A3 = “ABACABA”
  A4 = “ABACABADABACABA”
  … …
  你能找出其中的规律并写所有的数列AN吗?

输入格式

仅有一个数:N ≤ 26。

输出格式

请输出相应的字符串AN,以一个换行符结束。输出中不得含有多余的空格或换行、回车符。

样例输入

3

样例输出

ABACABA

解题步骤

观察这些字符串,不难发现

  A1 = “A
  A2 = “ABA
  A3 = “ABACABA
  A4 = “ABACABADABACABA

整体规律就是:AN=A(N-1)+第N号字母+A(N-1)

那么也可以用递归方法实现

直接利用找到的规律写出代码即可,注意字符转化

code

#include<bits/stdc++.h>
using namespace std;
string FJ(int N){
	if(N==1){
		return "A";
	}else{
		return FJ(N-1)+(char)('A'+N-1)+FJ(N-1);
	}
}
int main(){
	int N;
	cin>>N;
	cout<<FJ(N);
	return 0;
} 

题目三:递归实现指数型枚举

问题描述

从 1~n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。

输入格式

        输入一个整数n。

输出格式

        每行输出一种方案。同一行内的数必须升序排列,相邻两个数用恰好1个空格隔开。对于没有选任何数的方案,输出空行。各行(不同方案)之间的顺序任意。

数据范围

        1 ≤ n ≤ 15

示例

        输入 :3

        输出:1,12,13,123,2,23,3

        输入 :4

        输出:1,12,13,14, 123,134, 1234, 2,23,24, 234, 3, 34, 4

解题步骤

观察题目和示例,可以看到这个n既是输出的最大长度,也是所取数字的最大值

组合成的每一个数字实际上有重复关系,使用递归法

观察输出,实际上是对1~n中每个数字的选与不选

即取n时与取n-1时的区别在于增加了n这个数字所组成的组合(单层递归)

	dfs(index+1,n,current);//不选择该数字 ,即n-1产生的所有答案
	
	current.push_back(index);//index加入该数字 
	dfs(index+1,n,current);//生成新的组合 

规定同一行的数必须升序排列,那么第一个元素的大小还决定了该行答案出现数字的下界,并且第一个元素是从1,2,3,,,n

那么递归的终止条件为

	if(index>n){
		for(int i=0;i<current.size();i++){
			cout<<current[i]<<" ";
		}
		cout<<endl;
		return;
	}

 dfs具备以上两个主要部分后,只剩下确定参数啦

n作为上界是必须一直使用的,index作为下界需要在传递过程中改变,答案数组current也需要传递使用

那么整个函数的定义为void dfs(int index,int n,vector<int> current){

在主函数中完善输入,调用函数即可实现该题

code

#include<bits/stdc++.h>
using namespace std;
void dfs(int index,int n,vector<int> current){
	if(index>n){
		for(int i=0;i<current.size();i++){
			cout<<current[i]<<" ";
		}
		cout<<endl;
		return;
	}
	
	dfs(index+1,n,current);//不选择该数字 
	
	current.push_back(index);//index加入该数字 
	dfs(index+1,n,current);//生成新的组合 
}

int main(){
	int n;
	cin>>n;
	
	vector<int> current;
	dfs(1,n,current);
	return 0;
}

题目四:递归实现排列型枚举

问题描述

1-n个这 n 个整数拍成一排并打乱次序,输出所有可以选择的方案。

示例

        输入:3

        输出:

        123

        132

        213

        231

        312

        321

解题步骤

这个题目如果直接用笔算的话,可以看成是三个格子的填空游戏

从1开始作为第一位,再从余下的数字选择填入,是全排列

利用递归解决还是需要3步走

确定终止条件

如果第一位大于n那么结束,并输出该序列

    if(i>n){
		for(int j=1;j<=n;j++){
			cout<<s[j]<<" ";
		}
		cout<<endl;
		return;
	}

按顺序给1,2,3,4,,,n这n个数字一个当老大的机会,并逐步确定后面的小弟队伍

注意记录每一位小弟的排队情况(即有无使用过)

排进去后进行下一位,

递归完毕后会开启新一轮,需要恢复当前值和当前结果数组的使用情况(下一轮重新开始还得用呢!)

    for(int j=1;j<=n;j++){
		if(!used[j]){//该数字没有被使用过 
			s[i]=j;//记录该数字 
			used[j]=true;//更新记录情况
			dfs(i+1);//进行下一轮 
			used[j]=false;//回溯 
			s[i]=0;//清空 
		}
	}

 那么这个dfs的参数就比较简单了,只需要传入n即可void dfs(int i)

code

#include<iostream>
using namespace std;

const int N=10;
int n;
bool used[N];//记录数字是否用过 
int s[N];//保存方案 
void dfs(int i){
	if(i>n){
		for(int j=1;j<=n;j++){
			cout<<s[j]<<" ";
		}
		cout<<endl;
		return;
	}
	for(int j=1;j<=n;j++){
		if(!used[j]){//该数字没有被使用过 
			s[i]=j;//记录该数字 
			used[j]=true;//更新记录情况
			dfs(i+1);//进行下一轮 
			used[j]=false;//回溯 
			s[i]=0;//清空 
		}
	}
}
int main(){
	cin>>n;
	dfs(1);
	return 0;
}

题目五:递归实现组合型枚举

问题描述

1-n个数字中随机选取 m 个,每种方案按照里的数字按照从小到大的顺序排列,按照字典序输出。

示例

        输入:5 3

        输出:

        123

        124

        125

        134......

        345

解题步骤

这题不一样之处在于它多了个m,由两个值决定取值范围,取值个数

思路还是一样的

先写出终止条件,如果当前数大于最大取值个数m,输出当前序列

	if(now>m){
		for(int i=1;i<=m;i++){
			cout<<s[i]<<" ";
		}
		cout<<endl;
		return;
	} 

 单层递归呢就是,从当前遍历到的数字一直到n中,遍历选择,存入s中,再取下一位

	for(int i=start;i<=n;i++){//可用范围内随意挑选 
		s[now]=i;
		dfs(now+1,i+1);
		s[now]=0;
	}

 那么函数的参数需要当前值和开始值void dfs(int now,int start)

除此以外该函数可以再加一个剪枝操作,不做无用功

if(now+n-start<m)    return;//不够用

同样在主函数中进行输入和传参调用即可

code

#include<iostream>
using namespace std;
const int N=35;
int n,m;
int s[N];
void dfs(int now,int start){
	if(now+n-start<m)	return;//不够用
	if(now>m){
		for(int i=1;i<=m;i++){
			cout<<s[i]<<" ";
		}
		cout<<endl;
		return;
	} 
	for(int i=start;i<=n;i++){//可用范围内随意挑选 
		s[now]=i;
		dfs(now+1,i+1);
		s[now]=0;
	}
}
int main(){
	cin>>n>>m;
	dfs(1,1);
	return 0;
}

练习题!

我在速成蓝桥杯大神,你也来练一道吧!点击下方连接加入,为我砍一题!

 P8707 [蓝桥杯 2020 省 AB1] 走方格 - 洛谷

【蓝桥杯真题】 | 走方格(2020省赛)-CSDN博客

相关文章:

  • CTP开发爬坑指北(九)
  • spring声明式事务原理01-调用第1层@Transactional方法(事务访问入口)
  • [蓝桥杯]花束搭配【算法赛】
  • Ubuntu从源码安装Webots
  • 网络编程、URI和URL的区别、TCP/IP协议、IP和端口、URLConnection
  • MySQL相关参数
  • 【C++多线程】thread
  • SDL3 游戏开发 Windows 环境搭建
  • 介绍如何使用YOLOv8模型进行基于深度学习的吸烟行为检测
  • Matlab 矢量控制和SVPWM的感应电机控制
  • 算法——图论——关键活动
  • Blender插件NodeWrangler导入贴图报错解决方法
  • Docker生存手册:安装到服务一本通
  • Razor C# 变量
  • 数据结构(全)
  • 机器学习 [白板推导](二)[线性回归]
  • 第四章-PHP文件包含
  • JavaScript性能优化的12种方式
  • 【开原宝藏】30天学会CSS - DAY1 第一课
  • SOA(面向服务架构)与微服务架构的区别与联系
  • 南宁有本地租房做网站吗/外包公司和劳务派遣的区别
  • 360神搜网站建设/51link友链
  • 怎么看网站是用什么程序做的/逆冬seo
  • 外国做问卷可以赚钱的网站/seo在线优化网站
  • 哪里的网站可以做围棋死活题/手机app免费制作平台
  • 建设国家标准官方网站/知名的网络推广