首页
学习
活动
专区
圈层
工具
发布

【算法】递归的艺术:从本质思想到递归树,深入剖析算法的性能权衡

操作的数据结构是递归的场景: 树的相关操作:遍历、搜索、计算深度、计算结点数量…… 链表:将长度为 n 的链表 = 1 个结点 + 长度为 (n - 1) 的链表 图的深度优先遍历 需要 回溯 算法的问题...int 当值的大小超过 INT_MAX 时,函数的返回类型可以定义为 long long 这里我们就以 int 型为例,来定义递归函数: int Factorial(int n) { } 5.2 寻找递归基...n * Factorial(n - 1); } 说明这么多,那么递归算法具体是如何实现的呢?...它是理解递归工作原理、分析递归算法时间复杂度的强大工具。 这里我们以 阶乘问题 的递归算法为例: flowchart TB a[5!]--->b[5] a--->c[4!]...这种思想在数学定义递归的问题(如阶乘、斐波那契数列)、递归数据结构(树、链表)以及需要回溯算法的问题中表现出色。

57010
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    每日一题《剑指offer》链表篇之从尾到头打印链表

    但是我们都知道递归是到达底层后才会往上回溯,因此我们可以考虑递归遍历链表,因此三段式如下: 终止条件: 递归进入链表尾,即节点为空节点时结束递归。 返回值: 每次返回子问题之后的全部输出。...具体做法: step 1:我们可以顺序遍历链表,将链表的值push到栈中。 step 2:然后再依次弹出栈中的元素,加入到数组中,即可实现链表逆序。...具体做法: step 1:我们可以顺序遍历链表,将链表的值push到栈中。 step 2:然后再依次弹出栈中的元素,加入到数组中,即可实现链表逆序。...举例 解题思路 方法一:迭代 将链表反转,就是将每个表元的指针从向后变成向前,那我们可以遍历原始链表,将遇到的节点一一指针逆向即可。指针怎么逆向?不过就是断掉当前节点向后的指针,改为向前罢了。...返回值: 每次返回拼接好的较大部分的子链表。 本级任务: 每级不断进入下一个较小的值后的链表部分与另一个链表剩余部分,再将本次的节点接在后面较大值拼好的结果前面。

    33410

    equals 和 hashCode 到底有什么联系?一文告诉你!

    可以看出,hashCode()是一个native方法,而且返回值类型是整形;实际上,该native方法将对象在内存中的地址作为哈希码返回,可以保证不同对象的返回值不同。...JDK中对hashCode()方法的作用,以及实现时的注意事项做了说明: 1)hashCode()在哈希表中起作用,如java.util.HashMap。...,则将该对象加入到链表中。...long,再用规则(3)去处理long,得到int; 6) 如果是对象应用,如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。...java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上。 C、最后,把每个域的散列码合并到对象的哈希码中。  下面通过一个例子进行说明。

    84030

    Python函数与码复用

    以如下代码为例,说明调用过程:图片首先,程序会查找定义的函数fact,并将给定的参数10赋给这个函数的占位参数n,此时10就代替了定义函数中的n。...对于要实现的算法,如果设定了功能模块并且在功能模块之间建立关系,那么一个程序就能够被表达清楚。在模块化设计的思想中,需要关注一个程序的主程序、子程序和子程序之间的关系。...这就是一种递归形式。在递归的定义中有两个关键的特性:链条和基例。链条指的是在递归定义中,它的计算过程是存在一种递归有序的链条关系,例如:n!=n*(n-1)!,那么n!与(n-1)!就构成了递归链条。...基例指的是存在一个或多个不需要再次递归的实例,例如:当n=0时,定义n!的值为1,这就是一种基例,它与其它的值之间不存在递归关系,它已是递归的最末端。...接着在函数内部,需要区分基例和链条,所以要使用一个分支语句对输入参数进行判断,如果输入参数是基例的参数条件,我们就要给出基例的代码,如果不是基例的参数条件,我们要用链条的方式表达这种递归关系。

    57810

    CVTE2016春季实习校招技术一面回忆(C++后台开发岗)

    以非递归版本为例: else //找到 while(array[--mid]==value); return mid+1; 下面是关于Linux环境编程的相关知识点。...通过fork()的返回值来判断当前进程是父进程还是子进程,父进程返回子进程的进程ID,子进程返回0,如果fork失败,返回-1,错误号保存在errno中。...具体实现参考:十种常见排序算法。 问题十四: 手写代码,反转单链表。 答: 这个不需要什么算法思想,只要对链表节点逐个操作即可。...对于g++,实现上和VC++不同,它并没有生成独立的虚基类表和虚基类表指针来指明虚基类的偏移地址,具体实现细节我还不太清楚,可能《深度探索c++对象模型》会有说明。...,可以参考 C++中的单例模式。

    81311

    【JS】206-数据结构之链表,这一篇就够了

    欢喜之余,不由得思考背后的原因,前端er离数据结构与算法太遥远了,论坛里也少有人去专门为数据结构与算法撰文,才使得这看似平平的文章收获如此。...不过,这样也更加坚定了我继续学习数据结构与算法的决心(虽然只是入门级的) 一、链表数据结构 相较于之前学习的 栈/队列 只关心 栈顶/首尾 的模式,链表更加像是数组。...链表和数组都是用于存储有序元素的集合,但有几点大不相同 链表不同于数组,链表中的元素在内存中并不是连续放置的 链表添加或移除元素不需要移动其他元素 数组可以直接访问任何一个位置的元素,链表必须从表头开始迭代到指定位置访问..._head); 3.3 链表逆向输出 利用递归,反向输出 function _reversePrint(node){ if(!...双向链表和普通链表的区别在于,在链表中,一个节点只有链向下一个节点的链接,而在双向链表中,链接是双向的:一个链向下一个元素,另一个链向前一个元素,如下图 ?

    77940

    单链表逆序

    很多公司的面试题库中都有这道题,有的公司明确题目要求不能使用额外的节点存储空间,有的没有明确说明,但是如果面试者使用了额外的节点存储空间做中转,会得到一个比较低的分数。...首先从A节点开始逆序,将A节点的next指针指向prev,因为prev的当前值是NULL,所以A节点就从链表中脱离出来了,然后移动head和next指针,使它们分别指向B节点和B的下一个节点C(因为当前的...逆向节点A之后,链表的状态如图(2)所示: ?...()对问题进行求解,将链表分为当前表头节点和其余节点,递归的思想就是,先将当前的表头节点从链表中拆出来,然后对剩余的节点进行逆序,最后将当前的表头节点连接到新链表的尾部。...可以看出这个算法的核心其实是在回朔部分,递归的目的是遍历到链表的尾节点,然后通过逐级回朔将节点的next指针翻转过来。

    90630

    【数据结构】链表

    大纲 1、移除链表元素-(解析)-设置一个头节点 2、 设计链表-(解析)-基操 3、反转链表-(解析)-临时节点的优雅运用 4、两两交换链表中的节点-(解析)-优雅运用临时节点 5、删除链表的倒数第...[0, 5000] -5000 <= Node.val <= 5000 进阶:链表可以选用迭代或递归方式完成反转。...样例输入 样例输出 2 3 4 5 1 样例说明 样例中的数组变化如下: [1,2,3,4,5]→[3,1,2,4,5]→[2,3,1,4,5]→[2,3,4,5,1][1,2,3,4,5]→[3,1,2,4,5...样例输入 5 3 L 3 L 2 R 1 样例输出 2 3 4 5 1 样例说明 样例中的数组变化如下: [1,2,3,4,5]→[3,1,2,4,5]→[2,3,1,4,5]→[2,3,4,5,1][...(如食谱、整理文件) 算法的核心并不依赖于数学,而是基于明确的步骤与逻辑去解决问题,这才是关键。 数学更多的只是起到优化算法的作用。 借鉴博客: 1、什么是链表?

    42310

    JavaScript 数据结构之链表,这一篇就够了

    欢喜之余,不由得思考背后的原因,前端er离数据结构与算法太遥远了,论坛里也少有人去专门为数据结构与算法撰文,才使得这看似平平的文章收获如此。...不过,这样也更加坚定了我继续学习数据结构与算法的决心(虽然只是入门级的) 一、链表数据结构 相较于之前学习的 栈/队列 只关心 栈顶/首尾 的模式,链表更加像是数组。...链表和数组都是用于存储有序元素的集合,但有几点大不相同 链表不同于数组,链表中的元素在内存中并不是连续放置的 链表添加或移除元素不需要移动其他元素 数组可以直接访问任何一个位置的元素,链表必须从表头开始迭代到指定位置访问..._head); 3.3 链表逆向输出 利用递归,反向输出 function _reversePrint(node){ if(!...双向链表和普通链表的区别在于,在链表中,一个节点只有链向下一个节点的链接,而在双向链表中,链接是双向的:一个链向下一个元素,另一个链向前一个元素,如下图 正是因为这种变化,使得链表相邻节点之间不仅只有单向关系

    71020

    LeetCode每日一题-3:回文链表

    我们可以将链表的前(后)半部分反转(修改链表结构),然后将前半部分和后半部分进行比较。比较完成后我们应该将链表恢复原样。虽然不需要恢复也能通过测试用例,但是使用该函数的人通常不希望链表结构被更改。...在并发环境下,函数运行时需要锁定其他线程或进程对链表的访问,因为在函数执行过程中链表会被修改。 整个流程可以分为以下步骤: 找到前(后)半部分链表的尾节点。 反转(前)后半部分链表。 判断是否回文。...: currentNode 指针是先到尾节点,由于递归的特性再从后往前进行比较。...frontPointer 是递归函数外的指针。若 currentNode.val != frontPointer.val 则返回 false。...算法的正确性在于递归处理节点的顺序是相反的,而我们在函数外又记录了一个变量,因此从本质上,我们同时在正向和逆向迭代匹配。 所谓递归,即从上往下递下去,然后再从下往上归回来。

    31420

    【算法】递归算法的深度实践:深度优先搜索(DFS)从原理到LeetCode实战

    在前面的内容中,我们共同探索了汉诺塔的奥秘,体验了快速幂算法的高效,感受到了递归思维解决复杂问题的独特魅力。今天,我们将沿着递归这条主线继续前行,探索它在数据结构中的一个重要应用场景。...一、基本概念 1.1 遍历 基本定义:遍历​ (Traversal)是一种算法过程,指的是按照某种规则,系统地访问数据结构(如数组、链表、树、图)中的每一个节点(元素)一次且仅一次的过程。...这里我们以 树 为例来说明该算法的具体实现; 2.1 树中的深度优先搜索 深度优先搜索 的特性是 LIFO,该特性与树中的中序遍历一致,也就是说当我们在对树进行带有特定条件的中序遍历时,我们就是在对该棵树进行...在 树 中,各种操作是否能够执行,取决于当前访问的树是否为空树,因此在 树 中,其递归基可以直接通过判断该树是否为空树: if (root == NULL) { return NULL; } 2.4...ans —— 返回值变量 该函数只需要对 BST 进行一次 dfs ,因此函数不需要任何返回值,即,该函数的返回值为 void 3.3.2 递归基 在该算法中,控制算法的因素有两个: root ——

    74020

    【机器学习实战】第12章 使用FP-growth算法来高效发现频繁项集

    读取每个集合插入FP树中,同时用一个头部链表数据结构维护不同集合的相同项。...最终得到下面这样一棵FP树  从FP树中挖掘出频繁项集 步骤3: 对头部链表进行降序排序 对头部链表节点从小到大遍历,得到条件模式基,同时获得一个频繁项集。 ...条件模式基继续构造条件 FP树, 得到频繁项集,和之前的频繁项组合起来,这是一个递归遍历头部链表生成FP树的过程,递归截止条件是生成的FP树的头部链表为空。...我们得到的频繁项集有 t->ty->tyz->tyzx,这只是一小部分。 条件模式基:头部链表中的某一点的前缀路径组合就是条件模式基,条件模式基的值取决于末尾节点的值。...freqItemList = [] mineTree(myFPtree, myHeaderTab, 3, set([]), freqItemList) #递归的从FP树中挖掘出频繁项集。

    1.7K70

    详解equals()方法和hashCode()方法

    ()是一个native方法,而且返回值类型是整形;实际上,该native方法将对象在内存中的地址作为哈希码返回,可以保证不同对象的返回值不同。...JDK中对hashCode()方法的作用,以及实现时的注意事项做了说明: (1)hashCode()在哈希表中起作用,如java.util.HashMap。...,则将该对象加入到链表中。...long,再用规则(3)去处理long,得到int (6) 如果是对象应用,如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。...java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上。 C、最后,把每个域的散列码合并到对象的哈希码中。 下面通过一个例子进行说明。

    63610

    剑指offer | 面试题29:二叉搜索树转换为双向链表

    要求不能创建任何新的节点,只能调整树中节点指针的指向。 为了让您更好地理解问题,以下面的二叉搜索树为例: 难度:中等 我们希望将这个二叉搜索树转化为双向循环链表。...还需要返回链表中的第一个节点的指针。 解题思路: 本文解法基于性质:二叉搜索树的中序遍历为 递增序列 。...算法流程:dfs (cur):递归法中序遍历; 终止条件: 当节点cur为空,代表越过叶节点,直接返回; 递归左子树,即 dfs(cur. left) ; 构建链表: 当 pre 为空时:代表正在访问链表头节点...) ; 构建循环链表: 序遍历完成后,head 指向头节点,pre 指向尾节点,因此修改head 和pre的双向节点引用即可; 返回值: 返回链表的头节点head 即可; 复杂度分析: 时间复杂度0(N...,用于下层递归创建 pre = cur; dfs(cur.right); } /** * 思路:定义一个链表的尾节点,递归处理左右子树,最后返回链表的头节点

    59920

    详解 equals() 方法和 hashCode() 方法

    ()是一个native方法,而且返回值类型是整形;实际上,该native方法将对象在内存中的地址作为哈希码返回,可以保证不同对象的返回值不同。...JDK中对hashCode()方法的作用,以及实现时的注意事项做了说明: hashCode()在哈希表中起作用,如java.util.HashMap。...,则将该对象加入到链表中。...long,再用规则(3)去处理long,得到int 如果是对象应用,如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。...java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上。 C、最后,把每个域的散列码合并到对象的哈希码中。 下面通过一个例子进行说明。

    74730

    详解 equals() 方法和 hashCode() 方法

    ()是一个native方法,而且返回值类型是整形;实际上,该native方法将对象在内存中的地址作为哈希码返回,可以保证不同对象的返回值不同。...JDK中对hashCode()方法的作用,以及实现时的注意事项做了说明: (1)hashCode()在哈希表中起作用,如java.util.HashMap。...,则将该对象加入到链表中。...long,再用规则(3)去处理long,得到int (6) 如果是对象应用,如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。...java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上。 C、最后,把每个域的散列码合并到对象的哈希码中。 下面通过一个例子进行说明。

    74731

    详解 equals() 方法和 hashCode() 方法

    ()是一个native方法,而且返回值类型是整形;实际上,该native方法将对象在内存中的地址作为哈希码返回,可以保证不同对象的返回值不同。...JDK中对hashCode()方法的作用,以及实现时的注意事项做了说明: (1)hashCode()在哈希表中起作用,如java.util.HashMap。...,则将该对象加入到链表中。...long,再用规则(3)去处理long,得到int (6) 如果是对象应用,如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。...java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上。 C、最后,把每个域的散列码合并到对象的哈希码中。 下面通过一个例子进行说明。

    45410
    领券