递归、搜索与回溯算法——递归

26 篇文章 0 订阅

在这里插入图片描述

T04BF

👋专栏: 算法|JAVA|MySQL|C语言

🫵 小比特 大梦想

此篇文章与大家分享递归,搜索与回溯算法关于递归的专题
如果有不足的或者错误的请您指出!

1.什么时候使用递归

在遇到一道题的时候,如果我们发现一下几种情况,那么说明这道题可以使用递归来做
(1)这个问题可以被拆分成若干个小问题,且这些小问题和原来的主问题,有着一样的解决方法
(2)我们可以通过更小的子问题的解推出主问题的解
(3)当规模足够小的时候,可以直接求出答案

2.汉诺塔

题目:汉诺塔

2.1解析

在这里插入图片描述
如图所示,我们要将A柱的三个盘子,借助B柱,转移到C柱
那么我们的就需要分成三个大的步骤:

(1)将A柱的上面两个盘子,借助C柱,转移到B柱
(2)将A柱剩下的最大的盘子,放到C柱
(3)将B柱的两个盘子,借助A柱,转移到C柱

此时我们就能很明显的发现所谓的子问题,就是上面的(1)和(3),几个盘子,借助哪个盘子,转移到哪个盘子的问题
当我们仅有一个盘子的时候,那么直接将这个盘子移到C柱即可,即n = 1的时候,直接移动.这就是我们上面所说的,规模足够小的时候,可以直接得出答案
上面就是递归的精髓所在,我们完全可以将我们的递归函数看成 一个黑盒子,我们有理由完全相信这个黑盒子能够把我们的子问题解决,此外再找到规模足够小的时候,直接解决问题,作为递归的出口即可

2.2题解

class Solution {
    private void hanoi(List<Integer> pos1, List<Integer> pos2,List<Integer> pos3,int n) {
        if(n == 1) {
            pos3.add(pos1.remove(pos1.size()-1));
            return;
        }
        //将pos1的n-1盘子,借助C,移动到B
        hanoi(pos1,pos3,pos2,n-1);
        //将pos1剩下的一个盘子,移动到pos3
        pos3.add(pos1.remove(pos1.size()-1));
        //将pos2的n-1个盘子,借助pos1,移动到pos3
        hanoi(pos2,pos1,pos3,n-1);
    }
    public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
        hanoi(A,B,C,A.size());//主问题,将n个盘子,从A,借助B,移动到C
    }
}

3.合并两个有序链表

题目:合并两个有序链表

3.1解析

在这里插入图片描述

如图所示,如果我们要合并上述两个链表,那么就要分成3个步骤

(1)比较出两个链表头节点的大小,哪个小?记为node1
(2)将node1后面的节点形成的子链表,与另一个链表合并成有序链表,并将合并完后的头结点返回
(3)将node1的next指向(2)操作返回的头结点

此时我们就能很好的找到所谓的子问题,就是合并两个链表形成有序链表,就可以使用递归来做
那递归的出口是什么呢??
当我们其中的一条链表为空的时候,那么就直接返回第二个链表的头节点即可

3.2题解

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if(list1 == null) {
            return list2;
        }
        if(list2 == null) {
            return list1;
        }
        ListNode newHead = null;
        if(list1.val > list2.val){
            newHead = list2;
            newHead.next = mergeTwoLists(list2.next,list1);
        }else{
            newHead = list1;
            newHead.next = mergeTwoLists(list1.next,list2);
        }
        return newHead;
    }
}

4.翻转链表

题目:翻转链表

4.1解析

在这里插入图片描述
如图所示,我们要将上述链表翻转,就需要分成3步
(1)将除了头结点外,其余节点组成的子链表翻转,并将翻转完后的头结点返回
在这里插入图片描述
(2)将(1)中原来的头结点的next的next指向原来的头节点
(3)将原来头结点的next指向null
在这里插入图片描述
那么此时的子问题就是:将链表除了头结点外的部分进行翻转,并返回翻转完后的头结点,就可以使用递归来做
递归的出口是什么??当只有一个节点的时候,就直接返回这个节点即可,即当head.next == null时,返回head

4.2题解

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null) {
            return head;
        }
        ListNode newHead = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return newHead;
    }
}

5.两两交换链表中的节点

题目:两两交换链表中的节点

5.1解析

有了前两题的铺垫,这道题也是类似
在这里插入图片描述
要两两翻转链表中的节点,分为3步
(1)将第二个2个节点后的链表两两交换,返回交换完后的头结点
(2)将前两个加点交换
(3)将交换完后的节点与(1)返回的头结点连接
那么此时子问题就是 两两交换链表中的节点,就可以用递归来做
递归的出口就是:当只有一个节点或者节点为空的时候,直接返回这个节点即可

5.2解析

class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null) {
            return head;
        }
        ListNode newHead = swapPairs(head.next.next);
        ListNode next = head.next;
        next.next = head;
        head.next = newHead;
        return next;
    }
}

6.快速幂

题目:快速幂

6.1解析

快速幂是一种用于快速计算x 的 n次幂的算法
假设我们现在计算的是2 ^ 32
那么快速幂的思想就是
在这里插入图片描述
此时原来通过暴力解法,需要循环32次的计算,现在只需要5次即可
那么我们将问题拆分出来,要想求2 ^ 32 ,就要先求 2^16,即要先求 2 ^ (n/2)…
那么子问题就是,求出2的 n 次方 ,就可以使用递归来做
此时当n = 0的时候,就是递归的出口
但是如果n不是偶数,是奇数怎么办??
我们只需要提出其中的一个2即可
在这里插入图片描述

6.2题解

class Solution {
    private double pow(double x,long n) {
        if(n == 0) {
            return 1;
        }
        double tmp = pow(x,n/2);
        return n % 2 == 1 ? tmp * tmp * x : tmp * tmp;
    }
    public double myPow(double x, int nn) {
        long n = (long)nn;//防止越界
        return n < 0 ? 1.0 / pow(x,-n) : pow(x,n);//处理n 是负数的问题 
    }
}
感谢您的访问!!期待您的关注!!!

在这里插入图片描述

T04BF

🫵 小比特 大梦想
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值