【递归、搜索与回溯】递归算法

一、经验总结

在这里插入图片描述

递归 VS 迭代(循环)

递归和迭代都解决的是重复的子问题,因此两者是可以相互转化的。利用栈结构可以将递归算法转化为迭代算法。

递归和迭代各有其优缺点,选择时需根据具体场景和需求来决定。

  • 递归的优点包括:

    1. 简化问题:将大问题转化为小问题,减少代码量,使代码更简洁清晰,可读性更好。
    2. 有限语句定义无限集合:使用有限的循环语句实现无限集合的表示。
    3. 代码可读性好:递归代码通常更易于理解和维护。

    递归的缺点包括:

    1. 空间消耗大:递归调用会占用额外的栈空间,可能导致堆栈溢出。
    2. 效率较低:递归调用比迭代有更多的函数调用开销,可能影响运行效率。
    3. 需要设置结束条件:递归需要明确设置结束条件,否则可能导致无限递归至程序崩溃。
  • 迭代的优点包括:

    1. 高效率:迭代算法的效率较高,运行时间只随循环次数增加而增加,没有额外的空间开销。
    2. 空间效率高:迭代算法在空间上更为高效,没有递归的额外栈空间消耗。

    迭代的缺点包括:

    1. 代码不如递归简洁:迭代算法的代码可能不如递归算法简洁。
    2. 编写复杂问题时困难:迭代算法在处理复杂问题时可能不如递归算法直观和易于理解。

综上所述,递归和迭代都可以有效地解决问题,但选择哪种方法取决于问题的性质、代码的可读性和维护性要求以及运行时的性能需求。在实际应用中,大多数情况下迭代的效率更高,但递归在某些情况下提供了更简洁、更易于理解的解决方案。

递归 VS DFS

递归算法其实就是对递归决策树进行一次深度优先遍历(DFS),因此递归就是DFS。


二、相关编程题

2.1 汉诺塔

题目链接

面试题 08.06. 汉诺塔问题 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:
    void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {
        _hanota(A, B, C, A.size());
    }

    void _hanota(vector<int>& A, vector<int>& B, vector<int>& C, int n)
    {
        if(n == 1)
        {
            C.push_back(A.back());
            A.pop_back();
            return; //记得return
        }

        _hanota(A, C, B, n-1);
        C.push_back(A.back()); //这里不能写A[0]
        A.pop_back();
        _hanota(B, A, C, n-1);
    }
};

2.2 合并两个有序链表

题目链接

21. 合并两个有序链表 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        if(list1 == nullptr) return list2;
        if(list2 == nullptr) return list1;

        if(list1->val > list2->val)
            swap(list1, list2);

        list1->next = mergeTwoLists(list1->next, list2);
        return list1;
    }
};

2.3 反转链表

题目链接

206. 反转链表 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr) return nullptr;
        if(head->next == nullptr) return head;
        ListNode* newhead = reverseList(head->next);
        head->next->next = head;
        head->next = nullptr;
        return newhead;
    }
};

2.4 两两交换链表中的节点

题目链接

24. 两两交换链表中的节点 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head == nullptr || head->next == nullptr)
            return head;
        ListNode* next = head->next;
        ListNode* nnext = swapPairs(head->next->next);
        next->next = head;
        head->next = nnext;
        return next;
    }
};

2.5 快速幂

题目链接

50. Pow(x, n) - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {
public:
    double myPow(double x, long long n) {
        if(n == 0) return 1.0;
        if(n < 0) return 1.0/myPow(x, -n);
        double tmp = myPow(x, n/2);
        tmp *= tmp;
        return n%2==0? tmp:tmp*x;
    }
};

相关推荐

  1. 算法篇:搜索回溯算法

    2024-06-07 10:20:03       27 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-07 10:20:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-07 10:20:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-07 10:20:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-07 10:20:03       18 阅读

热门阅读

  1. IDM的优势

    2024-06-07 10:20:03       9 阅读
  2. docker错误

    2024-06-07 10:20:03       7 阅读
  3. golang通道(chan)选择(select)与关闭(close)使用示例

    2024-06-07 10:20:03       8 阅读
  4. vue3中作用域插槽

    2024-06-07 10:20:03       9 阅读
  5. Stable Diffusion:多领域应用的创新引擎

    2024-06-07 10:20:03       10 阅读
  6. npm发布自己的插件包

    2024-06-07 10:20:03       9 阅读
  7. 从零手写实现 nginx-09-compress http 文件压缩

    2024-06-07 10:20:03       9 阅读
  8. 从零手写实现 nginx-10-sendfile 零拷贝 zero-copy

    2024-06-07 10:20:03       6 阅读
  9. 0.3 数字电视简介

    2024-06-07 10:20:03       9 阅读
  10. ubuntu使用 .deb 文件安装VScode

    2024-06-07 10:20:03       11 阅读