合并两个有序单链表

132 阅读1分钟

leetcode 21题

注意的点

  • 插入位置可能是链表的末尾,则node.next是null,可能触发空指针。
  • 给出的数据中,两个链表都有可能是空的。注意考虑特殊情况。

我的版本

有根据数组创建单链表的代码,也有打印单链表的代码。

核心思想:遍历要插入的单链表,所有元素都插入为止。一层循环负责遍历新插入的链表,里面的循环负责寻找要插入到原链表的位置。

public class TestLeetcode21 {
    static class ListNode {
        int val;
        ListNode next;

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

    public static void main(String[] args) {
//        int[] list1 = {1, 2, 4};
//        int[] list2 = {1, 3, 4};
//        ListNode head = mergeTwoLists(createList(list1), createList(list2));
//        printList(head);
//
//        int[] list3 = {};
//        int[] list4 = {0};
//        ListNode head2 = mergeTwoLists(createList(list3), createList(list4));
//        printList(head2);

        int[] list5 = {2};
        int[] list6 = {1};
        ListNode head3 = mergeTwoLists(createList(list5), createList(list6));
        printList(head3);


    }

    public static ListNode createList(int[] nums) {
        if (nums != null && nums.length == 0) {
            return null;
        }
        ListNode head = new ListNode(nums[0]);
        ListNode cur = head;
        for (int i = 1; i < nums.length; i++) {
            cur.next = new ListNode(nums[i]);
            cur = cur.next;
        }
        printList(head);
        return head;
    }

    public static void printList(ListNode head) {
        while (head != null) {
            System.out.print(head.val);
            if (head.next != null) {
                System.out.print("->");
            }else{
                System.out.print("->null");
            }
            head = head.next;
        }
        System.out.println();
    }

    public static ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if (list1 == null) {
            return list2;
        } else {
            if (list2 == null) {
                return list1;
            }
        }
        //确定谁是等待插入的单链表
        ListNode waitForHead;
        ListNode newInsertHead;
        if (list1.val <= list2.val) {
            waitForHead = list1;
            newInsertHead = list2;
        } else {
            waitForHead = list2;
            newInsertHead = list1;
        }


        ListNode readNewInsert = newInsertHead;
        ListNode readWait = waitForHead;

        while (readNewInsert != null) {
            //寻找插入的位置
            while (!(
                    readNewInsert.val >= readWait.val &&
                    ((readWait.next==null)||
                            (readWait.next!=null&&readNewInsert.val <= readWait.next.val))
            )) {
                readWait = readWait.next;
            }
            //插入
            ListNode tempHead = readNewInsert.next;

            readNewInsert.next = readWait.next;
            readWait.next = readNewInsert;


            readNewInsert = tempHead;
        }
        return waitForHead;
    }
}

官方版本

核心思想:新生成一个-1节点,一重循环同时遍历两个链表,谁的节点小,就指向谁。

优点:代码简洁,思路清晰。

class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode prehead = new ListNode(-1);

        ListNode prev = prehead;
        while (l1 != null && l2 != null) {
            if (l1.val <= l2.val) {
                prev.next = l1;
                l1 = l1.next;
            } else {
                prev.next = l2;
                l2 = l2.next;
            }
            prev = prev.next;
        }

        // 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
        prev.next = l1 == null ? l2 : l1;

        return prehead.next;
    }
}