Java详解剑指offer面试题25--合并两个有序链表

Java详解剑指offer面试题25–合并两个有序链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

第一想到的就是归并排序了。

非递归版本

设置两个指针,p1指向链表1的头结点,p2指向链表2的头结点。先选出归并后链表的头结点:比较两个有序链表的头结点,哪个小即将其作为归并后链表的头结点并将相应的指针右移一步。接下来不断从两个链表中取较小值的结点插入到归并链表的末尾,分四种情况:

  • 链表1被取完了,直接将整条链表2插入到归并链表的末尾,归并结束;
  • 链表2被取完了,直接将整条链表1插入到归并链表的末尾,归并结束;
  • 如果不是以上两种情况,说明两个链表都还有元素,因此可以调用p1.val与p2.val比较(因此上面两条要先判断,否则可能会引发空指针异常),p1.val < p2.val时候,取链表1的结点,并将p1指针右移一步,归并链表的指针也要右移一步。
  • p1.val >= p2.val时,取链表2的结点,并将p2指针右移一步,归并链表的指针也要右移一步。

针对特殊输入:比如输入的其中一个链表为空,直接返回另外一个链表即可;如果输入的两个链表都为空,在前一种情况中已经包含了。

以上描述直接写成代码,如下:

package Chap3;

public class MergeTwoOrderedList {
    private class ListNode {
        int val;
        ListNode next = null;

        ListNode(int val) {
            this.val = val;
        }
    }

    /**
     * 非递归实现
     * @param list1 有序链表1
     * @param list2 有序链表2
     * @return 合并后的有序链表
     */
    public ListNode merge(ListNode list1, ListNode list2) {
        if (list1 == null) {
            return list2;
        }
        if (list2 == null) {
            return list1;
        }

        ListNode p1 = list1;
        ListNode p2 = list2;
        ListNode head = null;
        // 两个链表中哪个头结点的值小,就以此作为新链表的头结点
        if (p1.val <= p2.val) {
            head = p1;
            p1 = p1.next;
        } else {
            head = p2;
            p2 = p2.next;
        }

        ListNode cur = head;

        while (p1 != null || p2 != null) {
            // list1取完了,直接将p2全部插入到新链表后面,p2 =null表示添加完毕后立即终止
            if (p1 == null) {
                cur.next = p2;
                break;
                // list2取完了,直接将p1全部插入到新链表后面
            } else if (p2 == null) {
                cur.next = p1;
                break;
                // 否则只能一个个比较,将较小的插入到后面,同时指针移动
            } else if (p1.val < p2.val) {
                cur.next = p1;
                cur = cur.next;
                p1 = p1.next;
            } else {
                cur.next = p2;
                cur = cur.next;
                p2 = p2.next;
            }
        }
        return head;
    }
}

递归版本

从两个链表的头结点中选出值小的那个作为归并链表的头结点,此时该结点已经从链表中取出,头结点已经更新为原头结点的next,另一个链表的头结点保持不变。剩下的结点依然是有序的。然后继续归并两个链表中剩下的结点,继续比较两个链表头结点的值…这过程和上面一样了——典型的递归问题。

注意边界条件:当链表1头结点为空,此时就直接返回链表2的头结点,相当于直接和链表2相连了;同理当链表2头结点为空,此时就直接返回链表1的头结点,相当于直接和链表1相连了。这一点上和非递归版本是一样的。

package Chap3;

public class MergeTwoOrderedList {
    public ListNode mergeRecur(ListNode list1,ListNode list2) {
        if (list1 == null) {
            return list2;
        }
        if (list2 == null) {
            return list1;
        }

        ListNode mergedHead = null;
        if (list1.val < list2.val) {
            mergedHead = list1;
            mergedHead.next = mergeRecur(list1.next, list2);
        } else {
            mergedHead = list2;
            mergedHead.next = mergeRecur(list1, list2.next);
        }
        return mergedHead;
    }
}


本文参考文献:
[1]github.com/haiyusun/data-structures

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快乐李同学(李俊德-大连理工大学)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值