【算法】合并两个排序的链表

52 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第14天,点击查看活动详情

题目

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

例如:

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

解题思路

宏观理解:遍历两个链表数据比较大小后拼接即可。

  1. 拼接链表后如何找到头节点。
  2. 两个链表都是递增因此只需要比较大小最终链表还是递增。
  3. 两个链表长度不等需要判断某个链表先遍历结束的情况。

遍历双链表解法

  1. 因为遍历链表添加节点链表会后移,输出时需要知道链表第一个节点。因此增加一个空节点作为头节点定位。
  2. 遍历两个链表比较链表节点val大小来判定添加哪个链表节点并后移这个链表。
  3. 对两个链表判空处理,最后添加剩余链表的节点。
  4. 输出时跳过开始添加的空节点输出结果header.next。
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode header = new ListNode(0),next;
        next = header;
        while(l1 != null && l2 != null){
            if(l1.val > l2.val){ // 小于:链表先接入node2
                next.next = l2;
                l2 = l2.next;
            }else{ // 大于:链表先接入node1
                next.next = l1;
                l1 = l1.next;
            }
            next = next.next;
        }
        next.next = (l1 == null ? l2 : l1);
        return header.next;
    }

递归解法

  1. 终止条件是l1链表或者l2链表短了来判断输出另外一条链表。
  2. 比较链表当前节点大小判定移动哪条链表。
  3. 返回移动过的链表当前节点。
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1 == null) return l2; // l2比l1长
        if(l2 == null) return l1; // l1比l2长
        if(l1.val <= l2.val) {
            l1.next = mergeTwoLists(l1.next, l2); // l1值小移动l1
            return l1;
        } else {
            l2.next = mergeTwoLists(l1, l2.next); //l2值小移动l2
            return l2;
        }
    }

递归Tips

递归总是难以理解其实现,虽然代码简洁但需要一定理解成本。举例简单递归算法帮助理解递归本质实现。

public void fun(参数) {
    if (终止条件) {
        return;
    }
    fun(参数);
    (其他判断条件或语句);
}

举例题目

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

可用以下递归方法实现其算法,终止条件是n=1或是n=2;递归函数是n-1或是n-2。

public int climbStairs(int n){
    //终止条件
    if(n == 1)
        return 1;
    if(n == 2)
        return 2;
    //递归调用,此时青蛙可以选则跳一阶也可以跳两阶,所以将两种情况相加起来
    return climbStairs(n-1) + climbStairs(n-2);
}

模拟带入n值,当n=1时结果等于1;当n=2时结果等于2;当n=3时就会进入递归可知结果等于climbStairs(2) + climbStairs(1) = 1 + 2 = 3;当n=4时就是climbStairs(3) + climbStairs(2) = 3 + 2 = 5。

从上述模拟可知最终结果都是基于上次递归结果之上的,因此递归最主要的部分就是终止条件只要让递归函数知道其实结果是什么样并可知“未来情况”是什么样的。

参考