1

Time:2019/4/9
Title: Merge Two Sorted Lists
Difficulty: Easy
Author: 小鹿


题目:Merge Two Sorted Lists

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

Example:

Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4

Solve:

▉ 算法思路

1、正常思路,循环遍历迭代比较大小,每取出一个数据,将小数据加入到额外的数组中去,直到比较完毕,将其中一个剩余的数组追加到额外的数组尾部。

2、递归思路,满足递归的三个条件:

  • 将问题能不能化为子问题去解决?
  • 子问题的解决方式是否和总问题相似?
  • 是否有终止条件?
▉ 递归实现
var mergeTwoLists = function(l1, l2) {
    let result = null;
    //终止条件
    if(l1 == null) return l2;
    if(l2 == null) return l1;

    //判断数值大小递归
    if(l1.val < l2.val){
        result = l1;
        result.next = mergeTwoLists(l1.next,l2);
    }else{
        result = l2;
        result.next = mergeTwoLists(l2.next,l1);
    }

    //返回结果
    return result;
};
▉ 怎么理解递归?
其实递归最难的就是我们应该怎么去理解它,当我们完全理解了递归之后,就会发现递归非常方便,代码简洁。

我们经常理解递归会陷入到递归的细节上去,往往只递,归的时候就完全模糊了,我也试着找了网上的关于递归解释的,这么说吧,关于递归理解和使用,只有总结出自己的一套理解方法,才能真正的掌握递归,下面总结一下我自己理解的递归。

1、明确递归可以解决什么问题,也就是上边所讲到的解决的问题应该满足递归的三个条件。详细分开讲解:

  • 将问题划分为子问题:如果我们判断该问题可以用递归解决了,比如合并两个链表中比较结点大小,然后加入到新链表,然后在比较下一个结点大小,这个过程就是一个将问题化为子问题的过程,比较当前结点大小先要比较后一个节点与当前结点的大小,可以理解成“递”的过程。(就好比一扇扇包含关系的大门,问一共有几所大门,你拿着要是去打开,发现里边还有一扇,然后再打开,发现还有一扇,直到最后一扇。通常我们使用迭代循环来解决这个问题,就好比打开一扇大门就 加一;而递归要做的就是当大门全部打开的时候,从里往外走关闭大门的时候统计大门的数量)
  • 寻找终止条件:递归必须有个终止条件,也就是子问题的解决方案,如果没有终止条件,问题就不会得到解答。如上方合并链表的时候,经过递归不断的比较下一结点,知道其中一个链表比较完毕为空了,结果返回第二个链表,也就是达到了终止的条件,开始“归”的过程。
  • 递推公式:你会问了,怎么写出递推公式呢?既然终止条件有了,那我们开始找出递归公式,下面是我自己总结出来的经验。

    ① 一看参数和 return。什么意思呢?比如上方合并链表的代码,分别明确函数的参数和返回值是什么?参数是两个合并的链表结点头结点。返回值是合并后的链表。

    ② 二凑参数和return。就是说我们要去按照参数和返回值去用递归伪造它,比较完成第一个结点,当然传入第二个节点,返回第一个结点到新链表尾部,那么递归就会返回新链表的下一结点。要屏蔽掉递归的细节,只看参数和返回值。

▉ 递归缺点
有时候问题可以使用递归,但是由于递归的缺点会放弃使用。

1、递归警惕堆栈溢出。

2、警惕递归重复元素计算。

3、递归的高空间复杂度。

▉ 怎么正确写出递归代码?
1、将问题化为子问题。

2、解决子问题。

3、寻找终止条件。

4、写出递归公式。

5、将递推公式转化为代码。

欢迎一起加入到 LeetCode 开源 Github 仓库,可以向 me 提交您其他语言的代码。在仓库上坚持和小伙伴们一起打卡,共同完善我们的开源小仓库!
Github:https://github.com/luxiangqia...


小鹿
82 声望16 粉丝