• 算法-递归


    目录

    什么是递归?

    递归基本知识

    案例


    什么是递归?

    狭义:函数可以自己调用自己-代码层面

    广义:问题可以划分为小问题,将所有小问题解决,再将结果汇总,大问题便解决了-思想层面

    问题的复杂性取决于传递的参数和每次调用自身的次数

    函数调用的本质

    1. function A(a){
    2. return a;
    3. }
    4. function B(b){
    5. return A(5)+b;
    6. }
    7. B(10);

    执行B方法,将调用B函数的地址参数b=10压入栈,执行B方法,再将调用A方法的地址和参数参数a=5压入栈,再执行A方法,return返回时,返回的是上一个地址,也就是A(5)这个位置,将5代替了A(5),再从栈中取出b=10,再return到上一个地址

    递归基本知识

    方法的调用是栈的结构,在A方法中调用B方法,会把这两个方法入栈,先执行完B方法再执行A方法。

    如何设计递归

    • 找重复:找该问题规模更小的子问题
    • 找变化:变化的量作为传递的参数
    • 找边界:达到某个条件结束递归,避免死循环

    切蛋糕思维,等价转换思维...

    递归代码中展现的内容

    递归出口的判断

    +

    将大问题分解一步后的解决方式(传参)

    案例

    求阶乘

    1. static int f1(int num){
    2. if(num == 1) return 1;
    3. return num * f1(--num);
    4. }

    重复:n!=n*(n-1)!

    循环:n不断减小

    边界:n=1时结束

    打印i到j

    1. static void f2(int i,int j){
    2. if(i > j) return;
    3. System.out.println(i);
    4. f2(i+1,j);
    5. }

    重复:i到j    i+1到j  ...

    变化:i变化

    边界:i不能大于j

    数组求和

    1. static int f3(int[] arr,int length){
    2. if(length == 0) return 0;
    3. return arr[length-1]+f3(arr,--length);
    4. }

    字符串反转

     求ABCD的反转=求D+ABC的反转=求DC+AB的反转.....

    1. static String f4(String str,int end){
    2. if(end == -1){
    3. return "";
    4. }
    5. return str.charAt(end)+f4(str,end-1);
    6. }

    斐波那契序列

    1 1 2 3 5 8 13 每一项是前两项的和,求第n项

    1. public static int f1(int n){
    2. if(n==1 || n==2) return 1;
    3. return f1(n-1) + f1(n-2);
    4. }

    重复:每一项是前两项之和

    变化:每项的的前两项序号变化

    边界:前两位为1

    斐波那契的递归树

     递归的顺序是  f(10)-f(9)-f(8)-f(7)...  是后序遍历 

    最大公约数

    假设有两个数x和y,存在一个最大公约数z=(x,y),即x和y都有公因数z,
    那么x一定能被z整除,y也一定能被z整除,所以x和y的线性组合mx±ny也一定能被z整除。(m和n可取任意整数)

    对于辗转相除法来说,思路就是:若x>y,设x/y=n余c,则x能表示成x=ny+c的形式,将ny移到左边就是x-ny=c,由于一般形式的mx±ny能被z整除,所以等号左边的x-ny(作为mx±ny的一个特例)就能被z整除,即x除y的余数c也能被z整除。

    1. //最大公约数
    2. static int f2(int m,int n){
    3. if(m % n == 0) return n;
    4. return f2(n,m%n);
    5. }


    求m和n的最大公约数,假设为z,如果m能被z整除,n能被z整除,m%n的余数也能被z整除,如果z不是n,就需要缩小范围,m肯定比n大,n肯定比m%n的余数大,那么就从n和m%n这个范围内找

    插入排序递归方式

    对数组0-n排序  等价于  对数组的0-n-1个元素排序,把第n个元素插入到这个有序的序列中。

    1. //思路2
    2. static void f3(int[] arr,int k){
    3. //出口
    4. if(k == 0) return;
    5. //对前k-1个元素排序
    6. f3(arr,k-1);
    7. //把位置k的元素插入到前面的部分
    8. int x = arr[k]; //记录第k的元素
    9. int index = k-1;//前一个元素坐标
    10. while (index > -1 && x < arr[index]){ //从小到大排序,x与其他元素比较
    11. arr[index+1] = arr[index]; //k位置比k-1的元素小,就把k-1的元素放到k上
    12. index--;
    13. }
    14. arr[index+1] = x;
    15. }

    插入排序的思路有很多,对于1 3 5 7 2这个数组

    思路1:可以把待排序数字与每个进行比较和交换

    1 3 5 7 2->1 3 5 2 7->1 3 2 5 7->1 2 3 5 7

    思路2:交换是来回进行两次赋值,可看出方法1中很多赋值为2的操作是无效的,不如干脆最后只赋值一次

    1 3 5 7 2->1 3 5 7 7->1 3 5 5 7->1 3 3 5 7->12 3 5 7

    思路3:先比较找到属于2的坐标,然后将该位置以后的元素往后移动一个单位,再赋值过去

    1 3 5 7 2->1 3 3 5 7->1 2 3 5 7

    汉诺塔

    将所有盘子从A移动到B,每次只能移动一个盘子,移动过程中不允许大盘子在小盘子上面。

    将原问题划分是,划分后的子问题要和原问题有相同的形式。

    思路

    N从A移动到B,A是起始,B是终点,C是辅助

    等价于

    N-1从A移动到C,A为起始,C是重点,B是辅助

    N从A移动到B

    N-1从C移动到B,C是起始,B是重点,A是辅助

     依次类推

    把N-1移动到C

    等价于

    把N-2移动到B

    把N-1移动到C

    把N-2移动到C

    1. static void f5(int N,String from,String to,String help){
    2. if(N == 1){
    3. System.out.println("move "+N+" from "+from+" to "+to);
    4. return;
    5. }else {
    6. f5(N-1,from,help,to);
    7. System.out.println("move "+N+" from "+from+" to "+to);
    8. f5(N-1,help,to,from);
    9. }
    10. }

    二分查找的递归形式

    递归树的形式

    求阶乘的就是单分支,求斐波那契的是多分支,而这一个就是从多分支中选择一条路。

    斐波那契的子问题增长规模是以二的指数来增长。 

    1. static int f(int[] arr,int low,int high,int key){
    2. if(low > high)
    3. return -1;
    4. int mid = (low + high) / 2;
    5. int midVal = arr[mid];
    6. if(midVal < key)
    7. return f(arr,mid+1,high,key);
    8. else if (midVal > key)
    9. return f(arr,low,mid-1,key);
    10. else
    11. return mid;
    12. }

  • 相关阅读:
    替代安全指标(Surrogate Safety Measures (SSM) )
    看懂半年报里的“宝藏指标”:华大基因加大研发投入酝酿蝶变
    《昇思25天学习打卡营第17天|K近邻算法实现红酒聚类》
    python多进程中常用方法用法详解
    汇编语言快速回顾(以x86_64为例)
    CentOS/RHEL7环境下更改网卡名称为CentOS6的传统命名规则
    idea如何彻底完美地修改项目名,以及解决idea修改项目名后出现中括号[]的问题
    软件测试自动化的成本效益分析
    vue使用百度地图(vue-baidu-map)
    CMake 学习笔记
  • 原文地址:https://blog.csdn.net/weixin_52972575/article/details/125586317