【数据结构与算法】递推法和递归法解题(递归递推算法典型例题)

本文详细介绍了递推法和递归法在算法设计中的应用,包括斐波那契数列、数字三角形问题和扑克牌42点问题的例题。同时探讨了这两种方法的特点,以及C++STL中容器和数据结构的递归实现,如二叉树遍历和深度优先搜索。
摘要由CSDN通过智能技术生成

  1. 更多算法例题链接:
    【数据结构与算法】C++的 STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题

  2. 数据结构中二叉树遍历的应用的算法大多的基于递归法实现的,具体可参考文章: 【数据结构】树与二叉树遍历算法的应用(求叶子节点个数、求树高、复制二叉树、创建二叉树、二叉树存放表达式)

  3. 深度优先搜索算法也是基于递归法实现的,详细内容见文章: 【数据结构与算法】搜索算法(深度优先搜索 DFS和广度优先搜索 BFS)以及典型算法例题

【算法】递推法和递归法

递推算法递归算法是两种常用的算法思想,它们在解决实际问题时常常被使用。虽然它们的名称相似,但在实现和应用上存在一些区别。

递推算法

递推法的核心在于找到递推关系式。这种方法可以将复杂的计算过程转化为简单的重复步骤,充分利用计算机在运行程序时的时间局部性和空间局部性。

递推算法的特点

递推算法解题的基本思路:

  1. 将复杂计算转换为简单重复运算;
  2. 通过找到递推关系式进行简化运算;
  3. 利用计算机的特性,减少运行时间。
  4. 递推算法的一般步骤:

根据题目确定数据项,并找到符合要求的递推关系式;

  1. 根据递推关系式设计递推程序;
  2. 根据题目找到递推的终点;
  3. 单次查询可以不进行存储,
  4. 多次查询都要进行存储;
  5. 按要求输出答案即可。

递归算法

递归算法:递归算法是一种自顶向下的算法,它通过不断地直接或间接调用自身的函数,通过每次改变变量完成多个过程的重复计算,直到到达边界之后,结束调用。(与递推法相似的是,递归与递推都是将一个复杂过程分解为几个简单重复步骤进行计算。)

递归算法的实现的核心分治策略,即分而治之,将复杂过程分解为规模较小的同类问题,通过解决若干个小问题,进而解决整个复杂问题。

递归算法的特点

递归算法设计的一般步骤:

  1. 根据题目设计递归函数中的运算部分;
  2. 根据题目找到递归公式,题目可能会隐含给出,也可能需要自己进行推导;
  3. 找到递归出口,即递归的终止条件。

递归法与递推法的算法设计例题

例题一:斐波那契数列(递归递推两种方法 以及 改进算法)

在这里插入图片描述
分析得:

  1. 递推:
    这个题给出递推式
    F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n)=F(n−1)+F(n−2) F(n)=F(n1)+F(n2)
    转化为可用的递推关系,即
    F ( n ) + F ( n + 1 ) = F ( n + 2 ) F(n)+F(n+1)=F(n+2) F(n)+F(n+1)=F(n+2)

递推代码示例:

#include <iostream>
using namespace std;

int main()
{

    int n; //第几个数
    int x=0; //F(n)
    int y=1; //F(n+1)
    int ans; //F(n+2)

    cin>>n;

    if(n==0) ans=0;
    else if(n==1) ans=1;
    else {
        for(int i=2;i<=n;i++)
        {//递推
            ans=x+y;
            x=y;
            y=ans;
        }
    }
    cout<<ans<<endl;

}

改进算法(假如:将进行M次查询,每次输入一个N,其中n小于30):
存储型的递推

//每次查询后就存储下来 方便下次的查询
#include <iostream>
using namespace std;
int F[35];

void init()
{
    F[0]=0;

    F[1]=1;

    for(int i=2;i<=30;i++)
    {
        F[i]=F[i-1]+F[i-2];
    }//运行的时候 前三十个 每个都计算了
}
int main()
{

    int m; //m次查询
    int n; //第几个数
    init();

    cin>>m;

    while(m>0){
        m-=1;
        cin>>n;
        cout<<F[n]<<endl;
    }
}
  1. 递归
    递归表达式为:
    F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n)=F(n-1)+F(n-2) F(n)=F(n1)+F(n2)
    递归出口为:
//递归出口1
    if(n==0)
        return 0;

//递归出口2
    else if(n==1 )
        return 1;

递归代码示例:


#include <iostream>
using namespace std;

int fn(int n)
{
    //递归出口1
    if(n==0)
        return 0;

    //递归出口2
    else if(n==1 )
        return 1;
    else
        return fn(n-1)+fn(n-2); //递归关系式
}


int main()
{
    int n; //第几个数
    int ans;
    cin>>n;
    ans=fn(n);
    cout<<ans<<endl;

}

改进递归(假如:将进行M次查询,每次输入一个N,其中n小于30)算法:
存储型的递归

#include <iostream>
using namespace std;
int F[35];

int fn(int n)
{
    //递归出口1
    if(n==0)
    {
        F[0]=0;
        return 0;
    }

    //递归出口2
    else if(n==1 )
    {
        F[1]=1;
        return 1;
    }

    else
    {
        F[n]=fn(n-1)+fn(n-2);
        return F[n]; //递归关系式
    }
}

int main()
{
    int m; //m次查询
    int n; //第几个数

    fn(30);//一次性 全算了一遍
    cin>>m;

    while(m>0){//然后 直接输出结果
        m-=1;
        cin>>n;
        cout<<F[n]<<endl;
    }
}

例题二:数字三角形问题

在这里插入图片描述

输入样例:

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

输出样例:

30

分析题目可得递推表达式为:
a[i][j] = max{a[i][j]+a[i+1][j],a[i][j]+a[i+1][j+1]}
题解代码示例:

#include<iostream>
using namespace std;

int main()
{
    int n; //n层
    int a[101][101]; //路径矩阵
    cin>>n;

    //输入数字三角形的值
    for (int i=1; i<=n; i++)
    {
        for (int j=1; j<=i; j++)
        {

        cin>>a[i][j]; //输入原始数据

        }
    }

    //递推开始

    for (int i=n-1; i>=1; i--)//从最后一层逆推
    {
        for (int j=1; j<=i; j++)
        {

            if (a[i+1][j]>=a[i+1][j+1])
                a[i][j]+=a[i+1][j];     //路径选择

            else
                a[i][j]+=a[i+1][j+1];
        }
    }

    cout<<a[1][1]<<endl;
}

例题三:扑克牌42点问题

在这里插入图片描述
输入示例:

K A Q 6 2 3 
YES

在这里插入图片描述

在这里插入图片描述
第一步:对输入的数据进行处理

//对输入的数据 进行处理
for(int i=0;i<6;i++){
		char c;
		//scanf("%c",&c);
		cin>>c;
		if(c=='A')
			a[i]=1;
		else if(c=='J')
			a[i]=11;
		else if(c=='Q')
			a[i]=12;
		else if(c=='K')
			a[i]=13;
		else
			a[i]=(int)(c-'0');

	}

第二步:计算每种可能的结果

	ans[0].push_back(a[0]);
	for(int i=1;i<=5;i++){
		for(int j=0;j<ans[i-1].size();j++){
			ans[i].push_back(ans[i-1][j]+a[i]);
			ans[i].push_back(ans[i-1][j]-a[i]);
			ans[i].push_back(ans[i-1][j]*a[i]);
			ans[i].push_back(ans[i-1][j]/a[i]);
		}
	}

第三步:判断ans[5]中是否有42

int flag = 0;
	for(int i=0;i<ans[5].size();i++){
		if(ans[5][i]==42){
			flag=1;
			break;
		}
	}
	
	if(flag== 1)
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;

题解代码示例:

#include<iostream>
#include<vector>
using namespace std;

vector<int> ans[6]; //创建大一点 记录五次计算的结果
int a[6]={0}; //存放输入的六个数据

int main()
{
	for(int i=0;i<6;i++){
		char c;
		//scanf("%c",&c);
		cin>>c;
		// 根据输入字符的不同,赋予对应的值给a数组
		if(c=='A')
			a[i]=1;
		else if(c=='J')
			a[i]=11;
		else if(c=='Q')
			a[i]=12;
		else if(c=='K')
			a[i]=13;
		else
			a[i]=(int)(c-'0');

		}
	ans[0].push_back(a[0]);
	// 计算可能的运算结果
	for(int i=1;i<=5;i++){
		for(int j=0;j<ans[i-1].size();j++){
		 // 将上一步结果与a[i]进行加减乘除运算,并将结果添加到ans[i]中
			ans[i].push_back(ans[i-1][j]+a[i]);
			ans[i].push_back(ans[i-1][j]-a[i]);
			ans[i].push_back(ans[i-1][j]*a[i]);
			ans[i].push_back(ans[i-1][j]/a[i]);
		}
	}
	// 检查是否有结果等于42
	int flag = 0;
	for(int i=0;i<ans[5].size();i++){
		if(ans[5][i]==42){
			flag=1;
			break;
		}
	}
	
	if(flag== 1)
		cout<<"YES"<<endl;
	else
		cout<<"NO"<<endl;
	return 0;
 } 

感谢阅读!!!

  1. 更多算法例题链接:
    【数据结构与算法】C++的 STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题

  2. 数据结构中二叉树遍历的应用的算法大多的基于递归法实现的,具体可参考文章: 【数据结构】树与二叉树遍历算法的应用(求叶子节点个数、求树高、复制二叉树、创建二叉树、二叉树存放表达式)

  3. 深度优先搜索算法也是基于递归法实现的,详细内容见文章: 【数据结构与算法】搜索算法(深度优先搜索 DFS和广度优先搜索 BFS)以及典型算法例题

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chen_devy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值