【算法】递归

【ps】本篇有 5 道 leetcode OJ

目录

一、算法简介

二、相关例题

1)汉诺塔问题

[.1- 题目解析](#.1- 题目解析)

[.2- 代码编写](#.2- 代码编写)

2)合并两个有序链表

[.1- 题目解析](#.1- 题目解析)

[.2- 代码编写](#.2- 代码编写)

3)反转链表

[.1- 题目解析](#.1- 题目解析)

[.2- 代码编写](#.2- 代码编写)

4)两两交换链表中的节点

[.1- 题目解析](#.1- 题目解析)

[.2- 代码编写](#.2- 代码编写)

[5)Pow(x, n)](#5)Pow(x, n))

[.1- 题目解析](#.1- 题目解析)

[.2- 代码编写](#.2- 代码编写)


一、算法简介

常见的、典型的搜索算法有 BFS(宽度优先搜索)和 DFS(深度优先搜索)。

而递归是搜索算法的基础。如果将递归看作是一个大类,那么搜索算法就是递归下面的一个分支,因此要掌握搜索算法,就必须掌握递归。

【Tips】递归是什么?

简单来说,递归就是一个函数自己调用自己的行为。


【Tips】为什么会用到递归?

把一个问题看作是主要问题,这个主要问题可以划分为若干个相同的子问题,递归就主要针对这种场景。


【Tips】如何理解递归?

  1. 画递归展开的细节图(本质是对一棵树进行DFS);
  2. 借助二叉树的相关题目;
  3. 宏观看待递归的过程:不要在意递归展开的细节图!把递归的函数当成是一个黑盒,相信这个黑盒一定能完成任务!

【Tips】如何写好递归?

  1. 函数头的设计:先找到相同的子问题!
  2. 函数体的书写:只关心某一个问题是如何解决的!
  3. 递归函数的出口:问题不能再细分的临界条件!

二、相关例题

1)汉诺塔问题

面试题 08.06. 汉诺塔问题

.1- 题目解析

假设 n = 1,只有一个盘子,很简单,直接把它从 A 中拿出来,移到 C 上。

如果 n = 2 ,就要借助 B 了,因为小盘子必须时刻都在大盘子上面,共需要 3 步。

如果 n > 2 呢?思路和上面是一样的,我们可以把 n 个盘子看成两个部分,一部分有 1 个盘子,另一部分有 n - 1 个盘子,于是就将最初的 n 个盘子从 A 移到 C 的问题,转化成了将 n - 1 个盘子从 A 移到 C 的问题, 依次类推,直至转化成 1 个盘子的问题时,问题也就解决了。

如果原问题可以分解成若干个与原问题结构相同但规模较小的子问题,往往可以用递归的方法解决:

  1. n = 1 时,直接把盘子从 A 移到 C;
  2. n > 1 时,先把上面 n - 1 个盘子从 A 移到 B(子问题,递归);再将最大的盘子从 A 移到 C;最后将 B 上 n - 1 个盘子从 B 移到 C(子问题,递归)。

.2- 代码编写

cpp 复制代码
class Solution {
public:
    void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {
        dfs(A,B,C,A.size());
        //参数说明:待转移的盘子、中转位置的盘子、目的位置的盘子、转移的盘子个数
    }
    //1.函数头
    void dfs(vector<int>& A, vector<int>& B, vector<int>& C,int n)
    {
        //3.递归出口
        if(n==1)
        {
            C.push_back(A.back());
            A.pop_back();
            return;
        }
        //2.函数体
        dfs(A,C,B,n-1);
        C.push_back(A.back());
        A.pop_back();
        dfs(B,A,C,n-1);

    }
};

2)合并两个有序链表

21. 合并两个有序链表

.1- 题目解析

.2- 代码编写

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        return dfs(list1,list2);
    }
    ListNode* dfs(ListNode* l1,ListNode* l2)
    {
        if(l1==nullptr) return l2;
        if(l2==nullptr) return l1;
        if(l1==nullptr && l2==nullptr) return nullptr;

        if(l1->val<=l2->val)
        {
            l1->next=dfs(l1->next,l2);
            return l1;
        }
        else
        {
            l2->next=dfs(l1,l2->next);
            return l2;
        }
    }
};

3)反转链表

206. 反转链表

.1- 题目解析

.2- 代码编写

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head==nullptr || head->next==nullptr)return head;
        ListNode* newhead=reverseList(head->next);
        head->next->next=head;
        head->next=nullptr;
        return newhead;
    }
};

4)两两交换链表中的节点

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

.1- 题目解析

两两为一组进行逆置。

.2- 代码编写

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head==nullptr || head->next==nullptr)return head;
        ListNode* ret=head->next;
        ListNode* tmp=swapPairs(ret->next);
        ret->next=head;
        head->next=tmp;
        return ret;
    }
};

5)Pow(x, n)

50. Pow(x, n)

.1- 题目解析

本题涉及快速幂算法,用递归实现快速幂即可。

.2- 代码编写

cpp 复制代码
class Solution {
public:
    double myPow(double x, int n) {
        return n<0 ? 1.0/pow(x,-(long long)n) : pow(x,n);//细节问题
    }
    double pow(double x,long long n)
    {
        if(n==0)return 1.0;
        double tmp=pow(x,n/2);
        return n%2==0 ? tmp*tmp : tmp*tmp*x;
    }
};
相关推荐
哥不想学算法1 小时前
【C++】字符串字面量拼接
开发语言·c++
海石1 小时前
1500分的题目,确实有实力,不过还是我略胜一筹
算法·leetcode
海石1 小时前
【记忆化搜索】条条大路通AC,走好适合你的那一条,走到后再考虑走得快
算法·leetcode
Jerry3 小时前
LeetCode 151. 反转字符串中的单词
算法
gugucoding4 小时前
31. 【C语言】堆栈与队列的实现
c语言·开发语言·数据结构·链表
ChaoZiLL5 小时前
我的数据结构3——链表(link list)
数据结构·链表
a1117766 小时前
LM 算法迭代过程动画演示(SLAM)
算法
头茬韭菜6 小时前
Context 的生死抉择:四层压缩、截断算法与 Session Memory
算法·ai
Jerry6 小时前
LeetCode 541. 反转字符串 II
算法
Jerry6 小时前
LeetCode 344. 反转字符串
算法