今天刷第2道LeetCode题,合并两个有序链表:
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
我的解题思路:
1. 先判断边界条件,如果有任意一个链表为空,则直接返回其中不为空的链表
2. 然后在一个循环里面,同时从左往右遍历两个链表
3. 遍历过程中,依次比较两个链表的值,把较小值放入新链表中,然后将对应链表的指针往右移动一位
4. 重复步骤3,直到:遍历次数超出两个链表长度之和,或者任何一个链表已经遍历到了末尾,则跳出循环
5. 把未遍历完的链表的后续数值全部放入新链表中,结束
java实现如下:
public static ListNode mergeTwoLists(ListNode l1, ListNode l2) { //这两个判断可以不需要,因为循环里面已经有条件判断 /*if (l1 == null) { return l2; } if (l2 == null) { return l1; }*/ ListNode result = new ListNode(); //保存头指针,方便输出 ListNode resultHead = result; while (l1 != null && l2 != null) { if (l1.val <= l2.val) { //这里可以不new新的节点,可以节省空间; //但是注意,这种做法有个副作用,就是会改变原来的l1,l2的数据, // result.next = l1; //而这种做法,虽然耗费额外的空间,但是对于原来的数据l1和l2不会有影响 result.next = new ListNode(l1.val); l1 = l1.next; } else { // result.next = l2; result.next = new ListNode(l2.val); l2 = l2.next; } result = result.next; } //这几行代码可以用3元运算符 ? :替换,更加简洁 /*if (l1 != null) { result.next = l1; } if (l2 != null) { result.next = l2; }*/ result.next = l1 != null ? l1 : l2; return resultHead.next; }
官方题解是使用递归来实现的,
算法
我们直接将以上递归过程建模,首先考虑边界情况。
特殊的,如果 l1 或者 l2 一开始就是 null ,那么没有任何操作需要合并,所以我们只需要返回非空链表。否则,我们要判断 l1 和 l2 哪一个的头元素更小,然后递归地决定下一个添加到结果里的值。如果两个链表都是空的,那么过程终止,所以递归过程最终一定会终止。作者:LeetCode
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
/** * 官方题解 * 算法 * 我们直接将以上递归过程建模,首先考虑边界情况。 * 特殊的,如果 l1 或者 l2 一开始就是 null ,那么没有任何操作需要合并,所以我们只需要返回非空链表。否则,我们要判断 l1 和 l2 哪一个的头元素更小,然后递归地决定下一个添加到结果里的值。如果两个链表都是空的,那么过程终止,所以递归过程最终一定会终止。 * <p> * 注意,该方法会修改l1和l2的数据,l1变成了: 1->2->3->4->4,l2变成了:1->1->2->3->4->4,并且l2的第2个节点开始是引用的l1的数据,也就是两者是共享部分内存数据的。 * 而这种数据结构,如果被类似递归的方法重新调用的话,可能产生两个链表互相引用的情况,形成引用环,那在遍历两个链表时,就会陷入死循环,最后可能会导致内存耗尽系统崩溃。 * * @param l1 * @param l2 * @return practice.zxz.leetcode.two_sum.ListNode * @author Zxz * @date 2019/10/12 10:44 **/ public static ListNode mergeTwoLists2(ListNode l1, ListNode l2) { if (l1 == null) { return l2; } else if (l2 == null) { return l1; } else if (l1.val < l2.val) { l1.next = mergeTwoLists2(l1.next, l2); return l1; } else { l2.next = mergeTwoLists2(l1, l2.next); return l2; } } /** 作者:LeetCode 链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 */
递归算法实现起来,果然代码可读性更好一些。
但是递归算法会修改原有链表的数据,这是该算法的一个副作用,使用的时候要注意,否则可能导致问题(比如,再次该递归方法,那么最终的链表数据会导致循环引用,遍历时就会陷入死循环)