One written test a day-2020-9-19

One written test a day-2020-9-19

leetCode: 21. Merge two ordered linked lists (simple)

The two merged into a new list in ascending order of ascending list and returns. The new linked list is composed by splicing all the nodes of the given two linked lists.

Example:

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

Method 1: Recursion

Ideas

We can recursively define the merge operation in two linked lists as follows (ignoring boundary conditions, such as empty linked lists, etc.):

Insert picture description here

In other words, a node with the smaller head value of the two linked lists is merged with the result of the merge operation of the remaining elements.

algorithm

We directly model the above recursive process, and need to consider the boundary conditions.

If l1 or l2 is an empty linked list from the beginning, then there is no operation to merge, so we only need to return a non-empty linked list. Otherwise, we have to determine which of l1 and l2 the head node of the linked list has the smaller value, and then recursively decide the next node to be added to the result. If one of the two linked lists is empty, the recursion ends.

/**
 * 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) {
    
    
  	  if (l1 == null) {
    
    
            return l2;
        } else if (l2 == null) {
    
    
            return l1;
        } else if (l1.val < l2.val) {
    
    
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
    
    
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }

    }
}

Complexity analysis:

时间复杂度:O(n+m)O(n + m)O(n+m),其中 nnn 和 mmm 分别为两个链表的长度。因为每次调用递归都会去掉 l1 或者 l2 的头节点(直到至少有一个链表为空),函数 mergeTwoList 至多只会递归调用每个节点一次。因此,时间复杂度取决于合并后的链表长度,即 O(n+m)O(n+m)O(n+m)。

空间复杂度:O(n+m)O(n + m)O(n+m),其中 nnn 和 mmm 分别为两个链表的长度。递归调用 mergeTwoLists 函数时需要消耗栈空间,栈空间的大小取决于递归调用的深度。结束递归调用时 mergeTwoLists 函数最多调用 n+mn+mn+m 次,因此空间复杂度为 O(n+m)O(n+m)O(n+m)。

Insert picture description here

Method 2: Iteration

Ideas

We can implement the above algorithm in an iterative way. When both l1 and l2 are not empty linked lists, determine which of l1 and l2 has the smaller head node value, and add the node with the smaller value to the result. When a node is added to the result, it will correspond to the linked list The node of is moved back one bit.

algorithm

First, we set a sentinel node prehead, which allows us to return to the merged linked list more easily at the end. We maintain a prev pointer, and what we need to do is adjust its next pointer. Then, we repeat the following process until l1 or l2 points to null: If the value of the current node of l1 is less than or equal to l2, we connect the current node of l1 to the back of the prev node and move the pointer of l1 one bit backward. Otherwise, we do the same for l2. Regardless of which element we follow, we need to move prev one bit backward.

At the end of the loop, at most one of l1 and l2 is non-empty. Since the two input linked lists are in order, no matter which linked list is non-empty, all the elements it contains are larger than all the elements in the previously merged linked list. This means that we only need to simply connect the non-empty linked list to the back of the merged linked list and return to the merged linked list.

/**
 * 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) {
    
    
  	 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;
    }
}

Insert picture description here

Guess you like

Origin blog.csdn.net/qq_37924905/article/details/108683007