基础算法(二):迭代、递归与分治

前言

        在这篇文章中,荔枝会梳理一些迭代、递归和分治的基本概念。同时也会有样题示例辅助理解这三种算法的应用。


文章目录

前言

一、迭代

1.1 概念

1.2 样题示例

二、递归

2.1 概念

2.2 样题示例 

三、分治

总结


一、迭代

1.1 概念

        迭代和递归其实是不一样的,相较于递归,迭代更像是一种逼近真值的过程,即我们利用某一迭代关系式不断地通过旧值递推真值的过程。 在迭代算法中,至少存在一个迭代变量(或者叫做循环变量),同时我们需要建立一个迭代关系式以及迭代的终止条件。在任何一门语言的入门学习中,我们都会接触到循环语句,在每一个循环的过程中执行一定的算法其实就是迭代的过程。

1.2 样题示例

题目描述:

回文数其实就是正着反着读都是一样的数,现在需要编写一段程序,当我们输入一个整数后,判断该数字是不是一个回文数,是的话返回一个True,否则返回一个False。(数字的输入范围x<=1e9)

输入示例:

123321

输出示例:
True

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

int main(){
	int x,begin,end;
	cin>>x;
	int flag=1;
	if(x<0||x%10==0&&x!=0){
		flag=0;
	}
	int n=1;
	while(x/n>=10){
		n*=10;
	}

	while(x>0){
        //末位
		end=x%10;
        //首位
		begin=x/n;
		if(begin!=end){
			flag=0;
		}
		x=(x%n)/10;
		n=n/100;
	}
	
	if(flag){
		cout<<"True"<<endl;
	}else{
		cout<<"Flase"<<endl; 
	}
	return 0;
}

二、递归

2.1 概念

        递归算法的最基本的思想就是将一个大的问题分解成多个较小的子问题来解决,多个子问题所得到的结果就是整一个问题的真解,使用递归算法的时候我们通常利用某个函数直接或者间接的调用自身来实现。递归算法的两个最基本的特征就是结束条件自我调用。自我调用是调用多个子问题的过程、结束条件则定义了最简子问题的答案。为了更好理解我们先来举个例子:

def fun(x):
    flag = 1
    if x != 1:
        flag = x*fun(x-1)
        return flag

    else:
        return flag

        当我们在主函数中调用fun(5)的时候,进入递归过程:fun(5)=5*fun(4)=...=5*(4*(3*(2*fun(1))))=5*(4*(3*(2*1)))。从上面的代码我们可以看出递归其实就包含了两个过程:递推与回溯。

递归的缺点

        从上面的定义我们可以认识到,递归其实是通过堆栈的方式来实现的。这就会带来一个栈溢出的问题:每当主程序调用一个递归函数,进程栈就会增加一层栈帧,当需要递归的层数较多的时候,就可能会出现栈溢出的后果,递归会消耗大量的内存空间。

递归实际应用

简单的递归应用比如计算斐波那契数列、计算阶乘、解决杨辉三角的值求解,而具有递归性质的数据结构主要是:链表、树、图。 

2.2 样题示例 

题目描述

我们有由底至上为从大到小放置的 n 个圆盘,和三个柱子(分别为左/中/右即left/mid/right),开始时所有圆盘都放在左边的柱子上,按照汉诺塔游戏的要求我们要把所有的圆盘都移到右边的柱子上,要求一次只能移动一个圆盘,而且大的圆盘不可以放到小的上面。


请实现一个函数打印最优移动轨迹。


给定一个 `int n` ,表示有 n 个圆盘。请返回一个 `string` 数组,其中的元素依次为每次移动的描述。描述格式为: `move from [left/mid/right] to [left/mid/right]`

数据范围:1≤n≤16

输入示例

2

输出示例

["move from left to mid","move from left to right","move from mid to right"]

核心代码

class Solution {
public:
    vector<string> result;
    void hanoi(int n,string left,string mid,string right){
        //递归结束条件
        if(n==0) return;
        //不管n的值为什么,都可以分为第n个圆盘和n-1个圆盘这两个“大圆盘”,
        //整个过程就是将n-1个圆盘借助right放到mid柱上,第n个直接从left柱移动到right柱上,
        //最后mid柱子上的n-1个圆盘借助left柱放到right柱子上
        hanoi(n-1,left,right,mid);
        result.push_back("move from " + left + " to " + right);
//三个柱子代表的意义在移动圆盘后会随之发生改变,此时就需要随之改变传递到hanoi函数中的参数。
        hanoi(n-1,mid,left,right);
    }
    vector<string> getSolution(int n) {
        hanoi(n,"left","mid","right");
        return result;
    }
};

三、分治

        了解完递归算法,我们接着来学习分治思想就会比较容易了。大多数的分治思想都是通过递归来实现的,分治其实就是对大问题划分成若干个规模较小的、独立的子问题,这些子问题的解合并起来就是原问题的解。这些子问题不会重叠,如果对大问题划分出来的子问题出现了重叠我们一般采用动态规划来求解。

需要注意的是:递归与分治其实是不同的,递归其实更像是一种求解问题的手段、而分治则是一种解决问题的思想或者是方法论。


总结

        荔枝在这里应该还是讲清了递归是什么以及分治与递归的不同之处,最后荔枝给大家拜年啦哈哈哈,祝大家兔年大吉,前“兔”无量🥰

今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值