leetCode-21: 合并两个有序链表

题目描述:

将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

解题方法:

按照题目中的要求,我们知道待合并的两个链表都是升序有序的,所以我们就不需要考虑其他的特殊情况了。在此以 {1, 2, 3} 和 {2, 3, 4} 分别生成两个升序有序的链表来进行合并,代码如下:

public class ListNode {

    /**
     * 数据域
     */
    private int val;

    /**
     * 指向下一个节点的链接
     */
    private ListNode next;

    public ListNode(int val) {
        this.val = val;
        this.next = null;
    }

    /**
     * 打印链表
     * @param listNode
     */
    public static void display(ListNode listNode) {
        if (listNode == null) {
            return;
        } else {
            while (listNode.next != null) {
                System.out.print(listNode.val + " -> ");
                listNode = listNode.next;
            }
        }
        System.out.println(listNode.val);
    }

    /**
     * 获取链表中元素的个数
     * @param listNode
     * @return
     */
    public static int getSize(ListNode listNode) {
        int count = 0;
        if (listNode == null) {
            return count;
        } else {
            while (listNode != null) {
                count++;
                listNode = listNode.next;
            }
            return count;
        }
    }

    /**
     * 数组转链表
     * @param arrays
     * @return
     */
    public static ListNode arrayToListNode(int[] arrays) {
        if (arrays.length == 0) {
            return null;
        }
        // 用数组的第一个元素生成一个新的链表
        ListNode head = new ListNode(arrays[0]);
        // 声明前一个节点等于头节点
        ListNode pre = head;
        for (int i = 1; i < arrays.length; i++) {
            // 要插入的节点对象
            ListNode node = new ListNode(arrays[i]);
            // 前一个节点的 next 指向当前节点
            pre.next = node;
            // 更新前一个节点
            pre = node;
        }
        return head;
    }

    /** 
     * 合并两个有序链表
     * @param listNode1 
     * @param listNode2
     * @return
     */
    public static ListNode mergeTwoList(ListNode listNode1, ListNode listNode2) {
        // 定义一个 val 为 0,next 为空的链表
        ListNode listNode = new ListNode(0);
        // 声明当前节点
        ListNode cur = listNode;
        while (listNode1 != null && listNode2 != null) {
            if (listNode1.val < listNode2.val) {
                // 当前节点的 next 域连接较小的一个节点
                cur.next = listNode1;
                // 更新当前节点
                cur = cur.next;
                // 更新 listNode1
                listNode1 = listNode1.next;
            } else {
                cur.next = listNode2;
                cur = cur.next;
                listNode2 = listNode2.next;
            }
        }
        // 任一为空,直接连接另一条链表
        if (listNode1 == null) {
            cur.next = listNode2;
        } else {
            cur.next = listNode1;
        }
        return listNode.next;
    }

    public static void main(String[] args) {
        int[] arrays1 = {1, 2, 3};
        ListNode listNode1 = arrayToListNode(arrays1);
        System.out.println(getSize(listNode1));
        display(listNode1);
        int[] arrays2 = {2, 3, 4};
        ListNode listNode2 = arrayToListNode(arrays2);
        System.out.println(getSize(listNode2));
        display(listNode2);
        ListNode listNode3 = mergeTwoList(listNode1, listNode2);
        display(listNode3);
    }

}

根据以上代码,我们主要说明一下 mergeTwoList() 方法对两个待合并链表的处理过程。进入此方法之后,我们先定义一个最后返回的链表 listNode 和一个指向该链表的节点 cur,待合并的两个链表分别为 listNode1 和 listNode2。

listNode1、listNode2、listNode 此时的各节点的数据域和 next 域的情况如下图所示:我们可以认为此时 listNode1 链表的头节点就为第一个节点,数据域为 1,next 指向下一个存储了 2 的节点,listNode2 也类似,对于 listNode 来说,此时头节点的数据域为 0,next 域为空。

接下来我们进行主要的判断,即判断 listNode1 的头节点的数据域是否小于 listNode2 的头节点的数据域,如果是,则临时节点的 next 域指向 listNode1,然后更新临时节点和 listNode1:

进行一次判断之后,我们发现此时 listNode1 的头节点数据域为 2,listNode2 不变,listNode 的 next域已经连接了 listNode1,cur 位于 listNode 的第二个节点处:

 第二次判断之后:

 第三次判断后:

第四次判断后:

第五次判断之后:

第五次判断之后,listNode1 已经遍历完成了,所以不需要再走 while 循环去判断了,直接进行下一步当 listNode1 == null 的操作,执行之后:

此时我们直接返回 listNode.next 即可。打印出的合并之后的链表结构为:

除此之外,该题还有另外一种解法,即使用递归解决,每次都去找 listNode1 和 listNode2 中较小的节点去拼接 next 域。完整代码如下:

public class ListNode {

    /**
     * 数据域
     */
    private int val;

    /**
     * 指向下一个节点的链接
     */
    private ListNode next;

    public ListNode(int val) {
        this.val = val;
        this.next = null;
    }

    /**
     * 打印链表
     * @param listNode
     */
    public static void display(ListNode listNode) {
        if (listNode == null) {
            return;
        } else {
            while (listNode.next != null) {
                System.out.print(listNode.val + " -> ");
                listNode = listNode.next;
            }
        }
        System.out.println(listNode.val);
    }

    /**
     * 获取链表中元素的个数
     * @param listNode
     * @return
     */
    public static int getSize(ListNode listNode) {
        int count = 0;
        if (listNode == null) {
            return count;
        } else {
            while (listNode != null) {
                count++;
                listNode = listNode.next;
            }
            return count;
        }
    }

    /**
     * 数组转链表
     * @param arrays
     * @return
     */
    public static ListNode arrayToListNode(int[] arrays) {
        if (arrays.length == 0) {
            return null;
        }
        // 用数组的第一个元素生成一个新的链表
        ListNode head = new ListNode(arrays[0]);
        // 声明前一个节点等于头节点
        ListNode pre = head;
        for (int i = 1; i < arrays.length; i++) {
            // 要插入的节点对象
            ListNode node = new ListNode(arrays[i]);
            // 前一个节点的 next 指向当前节点
            pre.next = node;
            // 更新前一个节点
            pre = node;
        }
        return head;
    }

    /**
     * 合并两个有序链表--迭代
     * @param listNode1
     * @param listNode2
     * @return
     */
    public static ListNode mergeTwoList(ListNode listNode1, ListNode listNode2) {
        // 定义一个 val 为 0,next 为空的链表
        ListNode listNode = new ListNode(0);
        // 声明当前节点
        ListNode cur = listNode;
        while (listNode1 != null && listNode2 != null) {
            if (listNode1.val < listNode2.val) {
                // 当前节点的 next 域连接较小的一个节点
                cur.next = listNode1;
                // 更新当前节点
                cur = listNode1;
                // 更新 listNode1
                listNode1 = listNode1.next;
            } else {
                cur.next = listNode2;
                cur = cur.next;
                listNode2 = listNode2.next;
            }
        }
        // 任一为空,直接连接另一条链表
        if (listNode1 == null) {
            cur.next = listNode2;
        } else {
            cur.next = listNode1;
        }
        return listNode.next;
    }

    /**
     * 合并两个有序链表--递归
     * @param listNode1
     * @param listNode2
     * @return
     */
    public static ListNode mergeTwoList2(ListNode listNode1, ListNode listNode2) {
        if (listNode1 == null) {
            return listNode2;
        }
        if (listNode2 == null) {
            return listNode1;
        }
        if (listNode1.val < listNode2.val) {
            listNode1.next = mergeTwoList2(listNode1.next, listNode2);
            return listNode1;
        } else {
            listNode2.next = mergeTwoList2(listNode1, listNode2.next);
            return listNode2;
        }
    }

    public static void main(String[] args) {
        int[] arrays1 = {1, 2, 3};
        ListNode listNode1 = arrayToListNode(arrays1);
        System.out.println(getSize(listNode1));
        display(listNode1);
        int[] arrays2 = {2, 3, 4};
        ListNode listNode2 = arrayToListNode(arrays2);
        System.out.println(getSize(listNode2));
        display(listNode2);
        ListNode listNode3 = mergeTwoList2(listNode1, listNode2);
        display(listNode3);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值