记录一下自己学习递归的过程(未完)

递归
关注于把大问题分解为小问题,不要纠结于具体过程,完全可以把递归函数看作一个魔法函数,而自己的唯一任务是简化原始问题,就假设递归方法已经是完成的,要考虑的是如何使用这个已经存在的递归方法;
例题 Leetcode206题

给你单链表的头节点 `head` ,请你反转链表,并返回反转后的链表。

该题除了使用如下的迭代方法解决:
迭代方法
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */ class Solution { public ListNode reverseList(ListNode head) { ListNode pre=null; ListNode cur=head; while(cur!=null){ ListNode next=cur.next; cur.next=pre; pre=cur; cur=next; } return pre; } }

还可以使用递归的方式实现,代码更加简洁:
递归方法
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */ class Solution { public ListNode reverseList(ListNode head) { if(head==null){ return head; //如果当前节点为空则直接返回head } ListNode newHead = reverseList(head.next); head.next.next = newHead; head.next = null; return newHead; } }

递归图解 记录一下自己学习递归的过程(未完)
文章图片

【记录一下自己学习递归的过程(未完)】递归过程的调用以上图为例,小问题为对后面的节点进行反转,则reverseList返回的结果newHead就是后面的子链表反转后的结果,于是使反转得到的newHead的next指向当前的head,就实现了最简问题的反转,并使Head的next指向null。不要去纠结递归过程是怎样的,只要认为reverseList函数是一个已经存在的魔法函数并使用它的功能。
当然,使用递归的前提是它满足递归的几个条件:①可以大问题分成完全相同解决方法的小问题;②有终止条件③能调用自身。
数学归纳法 数学归纳法(Mathematical Induction, MI)是一种数学证明方法,通常被用于证明某个给定命题在整个(或者局部)自然数范围内成立。
最简单和常见的数学归纳法是证明当n等于任意一个自然数时某命题成立。证明分下面两步:
  1. 证明当n= 1时命题成立。
  2. 假设n=m时命题成立,那么可以推导出在n=m+1时命题也成立。(m代表任意自然数)
这种方法的原理在于:首先证明在某个起点值时命题成立,然后证明从一个值到下一个值的过程有效。当这两点都已经证明,那么任意值都可以通过反复使用这个方法推导出来。把这个方法想成多米诺效也许更容易理解一些。例如:你有一列很长的直立着的多米诺骨牌,如果你可以:
  1. 证明第一张骨牌会倒。
  2. 证明只要任意一张骨牌倒了,那么与其相邻的下一张骨牌也会倒。
    那么便可以下结论:所有的骨牌都会倒下。
递归与数学归纳法的相似性 数学归纳法中,n=1、2、3...N时,每一个n都映射于一个同样结构的问题,即从小问题一直归纳到大问题,g(n+1)=f(n);
接下来考虑递归,递归工作时,一般会从大问题开始,一直执行到小问题,再层层返回参数。就像一个人打开一个门里面还有一个,一直开到最后一个门(达到递归终止条件),然后从最后一个门往回走,每出一个门就带回一个门的信息,直到回到初始门,完成每个门的信息处理。返回参数的过程就像数学归纳法从小到大的归纳过程。
不同之处是,数学归纳法我们可以很清楚地知道每一步是如何运作计算的,而递归的过程比较难以想象,而递归过程并不是代码编写者需要关注的事,把递归函数当作一个已经具备目标要求功能的魔法函数,用就可以了。
迭代的条件 递归函数必须要有终止条件:要使一个递归方法正常工作,必须使其对于越来越简单的示例不能有无限的归纳序列;递归归纳必须能得到一个可以用其他方法得到的基本情况,否则递归会无限循环下去。
递归三要素
  1. 确定递归函数的参数和返回值。
    确定好哪些参数在传递过程中需要处理就在递归函数中加上这些参数,并且明确每次递归的返回值是什么,进而确定递归函数的返回类型。
  2. 确定终止条件。
    写完递归算法,程序运行的时候经常会遇到栈溢出的错误,原因是没写终止条件或者终止条件错误。操作系统执行递归时也是要用栈的接哦古保存每一层递归的信息的,如果递归没有终止,那么操作系统的内存必然会溢出。
  3. 确定单层递归的逻辑。
    确定每一层递归需要处理的信息。在这里会重复调用函数本身来实现递归过程。

    推荐阅读