算法学习:leetcode21 合并两个有序链表

题目:合并两个有序链表

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

示例:

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

这里要注意的是,题目要求使用单向链表来实现。如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        
    }
}

思路:其实这题就是要两个链表各取一个元素进行比较,谁小就拿走谁的node,放到最终结果链表中。被拿走的链表,指针后移一位,也就是指向当前的node的next node。

所以我们实现一个简洁版本的示例,具体逻辑都在代码的注释里:

public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        //这两个if进行空判断,如果l1为空返回l2,
        // 即使l2为空也没关系,两个都为空,
        // 本来也要返回空
        if(l1 == null) {
            return l2;
        }
        if(l2 == null) {
            return l1;
        }
        //创建一个返回ListNode
        ListNode result = new ListNode();
        //将返回的ListNode付给一个新的ListNode,
        // 作用是在后续操作,都操作ListNode,
        // result最后返回合并后的链表的起始地址
        ListNode resultCurr = result;
        //while就是循环比较两个链表的大小,放入resultCurr中
        while(l1 != null && l2 != null) {
            if(l1.val > l2.val) {
                resultCurr.next = l2;
                //被取走一个值的链表,指针需要往后挪一个
                l2 = l2.next;
            } else {
                resultCurr.next = l1;
                //被取走一个值的链表,指针需要往后挪一个
                l1 = l1.next;
            }
            resultCurr = resultCurr.next;
        }
        //这里处理的场景是l1和l2长度不一致的时候,
        // 其中一个链表短,while判断后结束了循环,
        // 另一个链表的剩下的元素,需要追加到resultCurr中
        resultCurr.next = l1 == null ? l2 : l1;
        //这里返回的是result.next,而不是result,
        // 是因为循环中上来赋值就是从result的next开始的,
        // 所以result第一个元素是空的,
        // 当然要从第二个元素开始返回
        return result.next;
    }

如果不明白上面return result.next的逻辑,可以将上面的代码做一下逻辑转换,也就是我对第一个元素正常赋值,最后返回的是也return result。

public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode result = new ListNode();
        if(l1 == null && l2 == null) {
            return null;
        }
        ListNode currL1 = l1;
        ListNode currL2 = l2;

        if(currL1 == null) {
            result = currL2;
            return result;
        }
        if(currL2 == null) {
            result = currL1;
            return result;
        }
        if(l1.val > l2.val) {
            ListNode v = new ListNode(l2.val);
            result = v;
            currL2 = l2.next;
        } else {
            ListNode v = new ListNode(l1.val);
            result = v;
            currL1 = l1.next;
        }

        ListNode resultCurr = result;
        while(currL1 != null || currL2 != null) {
            if(currL1 == null) {
                resultCurr.next = currL2;
                break;
            }
            if(currL2 == null) {
                resultCurr.next = currL1;
                break;
            }
            if(currL1.val > currL2.val) {
                resultCurr.next = currL2;
                currL2 = currL2.next;
            } else {
                resultCurr.next = currL1;
                currL1 = currL1.next;
            }
            resultCurr = resultCurr.next;
        }
        return result;
    }

这个逻辑要注意循环的控制:while(currL1 != null || currL2 != null),这里是如果其中一个为空了,也继续执行循环,在循环中将另一个链表剩余元素放到结果链表中。