递归版题解

这题曾经写过,原文点这里,之前对递归的图解有点简单。

这次把递归版本重新写了一下,着重于图解部分,将递归怎么一步步调用的,怎么一步步返回的详细画了一遍。

先来回顾下这道题目吧:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

递归的两个条件:

  1. 终止条件:当l1或者l2中有一个为空时,就返回
  2. 函数内要做什么:如果l1.val小于等于l2.val,那么将l1.next指向 l1的后续节点和l2中较小的一个

终止条件比较好理解,函数内做的事情就不那么好懂了 l1的后续节点和l2中较小的一个

如果是 l1.val<=l2.val,我们就能确定一个较小的节点了,也就是l1。因为链表还没结束,我们要继续比较,这时候比较的是l1.next和l2。

反之,如果是l1.val>l2.val,我们也能确定一个较小的节点,现在是l2.因为链表还没结束,我们继续比较,这时候比较的是l1和l2.next。

后面就是不断的递归,最终把整个链表给串起来。

java 合并两个bean java 合并两个有序链表_java 合并两个bean

java版本如下:

class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//递归的结束条件,如果l1和l2中有一个为空就返回
if(l1==null || l2==null) {
return (l1==null)? l2:l1;
		}
//如果l1的值<=l2的值,就继续递归,比较l1.next的值和l2的值
//l1.next和l2比较完后,会产生一个更小的节点x,将x加到当前l1的后面
if (l1.val<=l2.val) {
			l1.next = mergeTwoLists(l1.next,l2);
return l1;
//如果l1的值>l2的值,就继续递归,比较l1的值和l2.next的值
		} else {
			l2.next = mergeTwoLists(l1,l2.next);
return l2;
		}
	}
}

python版本如下:

class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
		:type l1: ListNode
		:type l2: ListNode
		:rtype: ListNode
		"""
#递归的结束点就是L1或者L2为空就返回
#如果L1为空就返回L2,L2为空返回L1
ifnot (l1 and l2):
return l1 if l1 else l2
#L1的val<=L2的val,那么继续递归
#当前L1的next指向一个递归函数
#意思是L1的下一个和L2哪个大,就作为当前L1的next
if l1.val<=l2.val:
			l1.next = self.mergeTwoLists(l1.next,l2)
return l1
else:
			l2.next = self.mergeTwoLists(l1,l2.next)
return l2

时间复杂度:O(n + m),其中 n 和 m 分别为两个链表的长度   

空间复杂度:O(n + m)

详解执行过程

我们定义两个链表:1->2->41->3->4L1即为第一个链表,L2为第二个链表

两个链表下方是代码部分,具体如下图所示:

java 合并两个bean java 合并两个有序链表_java 合并两个bean_02

再解释一下上图中代码部分:

  • 第一个if:递归的终止条件,如果链表1为空 或者 链表2为空就返回
  • 第二个if:如果链表1的节点值 <= 链表2的节点值,则继续下一层的递归比较
  • else部分:如果链表1的节点值 > 链表2的节点值,则继续下一层递归比较

后面我们就开始不断比较,不断调用下一层递归函数
每一步中,具体执行到哪段代码,我用红色标记出来了:


java 合并两个bean java 合并两个有序链表_java 合并两个bean_03

java 合并两个bean java 合并两个有序链表_链表_04

java 合并两个bean java 合并两个有序链表_递归函数_05

java 合并两个bean java 合并两个有序链表_合并两个有序链表 java_06

java 合并两个bean java 合并两个有序链表_递归函数_07

java 合并两个bean java 合并两个有序链表_递归_08

java 合并两个bean java 合并两个有序链表_java 合并两个bean_09

java 合并两个bean java 合并两个有序链表_递归函数_10

java 合并两个bean java 合并两个有序链表_合并两个有序链表 java_11

java 合并两个bean java 合并两个有序链表_递归函数_12

<<< 左右滑动见更多 >>>

  • 上图中第一步、第二步:当链表1的节点1 <= 链表2的节点1时候,让链表1的节点1.next指向下一层递归函数,但此时程序并没有执行完,链表1的节点1.next指向的还是一个未知的节点,到底会指向谁,需要等后面的递归函数执行完返回后才知道
  • 第三步、第四步:链表1的节点2>链表2的节点1,让链表2的节点1.next指向下一层递归函数,具体指向谁需要等后面的递归函数执行完返回后才知道
  • 第五步、第六步:链表1的节点2<=链表2的节点3,让链表1的节点2.next 指向下一层递归函数
  • 第七步、第八步:链表2的节点3.next 指向下一层的递归函数
  • 第九步、第十步:链表1的节点4.next 指向下一层递归函数

经过上面 10 步之后,递归调用就到头了,因为上图中最后一张图,最右边的黑色方框里只剩下一个4了。此时就会触发递归终止条件,然后不断返回


java 合并两个bean java 合并两个有序链表_java 合并两个bean_13

java 合并两个bean java 合并两个有序链表_链表_14

java 合并两个bean java 合并两个有序链表_递归_15

java 合并两个bean java 合并两个有序链表_链表_16

java 合并两个bean java 合并两个有序链表_链表_17

java 合并两个bean java 合并两个有序链表_递归_18

java 合并两个bean java 合并两个有序链表_链表_19

java 合并两个bean java 合并两个有序链表_java 合并两个bean_20

java 合并两个bean java 合并两个有序链表_合并两个有序链表 java_21

java 合并两个bean java 合并两个有序链表_java 合并两个bean_22

<<< 左右滑动见更多 >>>

再来分析一下上图中递归函数是怎么返回的:

  • 第11步:此时链表1为空,于是触发递归终止条件,返回链表2的节点4
  • 第12步:链表2的节点4返回到上一层递归函数,上一层函数是链表1的节点4,于是链表1的节点4.next 就指向 链表2的节点4
  • 第13步:链表1的节点4返回
  • 第14步:链表2的节点4返回到上一层递归函数,上一层函数是链表2的节点3,于是链表2的节点3.next 就指向 链表1的节点4
  • 第15步:链表2的节点3返回
  • 第16步:链表2的节点3返回到上一层递归函数,上一层的函数是链表1的节点2,于是链表1的节点2.next 就指向 链表2的节点3
  • 第17步:链表1的节点2返回
  • 第18步:链表1的节点2返回到上一层递归函数,上一层函数是链表2的节点1,于是链表2的节点1.next 就指向 链表1的节点2
  • 第19步:链表2的节点1返回
  • 第20步:链表2的节点1返回到上一层递归函数,上一层函数是链表的节点1,于是链表1的节点1.next 就指向 链表2的节点1

如下图所示,最后返回链表1的节点1,此时两个链表就被合并成一个链表了

java 合并两个bean java 合并两个有序链表_递归_23