[byte enterprise question bank] combination of linked list, two ordered linked lists, LRU cache mechanism, reverse linked list II [three questions a day]

Byte beating enterprise question bank and linked list series. Because leetcode members can see the enterprise question frequency, we brush from the highest to the lowest. There are 21 questions. Merge two ordered linked lists  , 146. LRU cache mechanism, 92. Reverse linked list II

21. Merge two ordered linked lists  

[simple] [Title Description] merge two ascending linked lists into a new one   Ascending order   Linked list and return. The new linked list is composed of all nodes of a given two linked lists.  
Example 1: input: l1 = [1,2,4], l2 = [1,3,4] output: [1,1,2,3,4,4]
Example 2: input: l1 = [], l2 = [] output: []
Example 3: input: l1 = [], l2 = [0] output: [0]

This problem is an old topic. It is a second kill for students who are familiar with the linked list. We solve the problem in two ways: recursion and iteration
[iteration, recursion] diagram:

/**
 * 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 {
    /* Recursive method: O(m+n), spatial complexity O(m+n) */
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        // If one of the two linked lists is empty, the recursion ends.
        if (l1 == null) {
            return l2;
        }
        if (l2 == null) {
            return l1;
        }
        // Judge which of l1 and l2 has the smaller value of the head node of the linked list, and then recursively determine the next node to be added to the result.
        if (l1.val < l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

  23. Merge K ordered linked lists

[difficulty] [Topic description] give you a linked list array, and each linked list has been arranged in ascending order. Please merge all linked lists into an ascending linked list and return the merged linked list.
Example 1: input: lists = [[1,4,5],[1,3,4],[2,6]] output: [1,1,2,3,4,4,5,6]
Explanation: the linked list array is as follows:
[
  1->4->5,
  1->3->4,
  2->6
]
Combine them into an ordered linked list.
1->1->2->3->4->4->5->6
Example 2: input: lists = [[]] output: []

[violence, recursion, iteration] diagram:

/**
 * 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 {
    /*K Pointer: K pointers point to K linked lists respectively; Each time O(K) compares K pointers min, time complexity O(NK)*/
    public ListNode mergeKLists(ListNode[] lists) { 
        int k = lists.length;
        ListNode dummyHead = new ListNode(0);
        ListNode tail = dummyHead;
        while (true) {
            ListNode minNode = null;
            int minPointer = -1;
            for (int i = 0; i < k; i++) {
                if (lists[i] == null) {
                    continue;
                }
                if (minNode == null || lists[i].val < minNode.val) {
                    minNode = lists[i];
                    minPointer = i;
                }
            }
            if (minPointer == -1) {
                break;
            }
            tail.next = minNode;
            tail = tail.next;
            lists[minPointer] = lists[minPointer].next;
        }
        return dummyHead.next;
    }
}
class Solution {
    /*Pairwise merge iteration*/
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists.length == 0) {
            return null;
        }
        int k = lists.length;
        while (k > 1) {
            int idx = 0;
            for (int i = 0; i < k; i += 2) {
                if (i == k - 1) {
                    lists[idx++] = lists[i];
                } else {
                    lists[idx++] = merge2Lists(lists[i], lists[i + 1]);
                }
            }
            k = idx;
        }
        return lists[0];
    }
}

class Solution {
    /*Merge two recursive*/
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists.length == 0) {
            return null;
        }
        return merge(lists, 0, lists.length - 1);
    }

    private ListNode merge(ListNode[] lists, int lo, int hi) {
        if (lo == hi) {
            return lists[lo];
        }
        int mid = lo + (hi - lo) / 2;
        ListNode l1 = merge(lists, lo, mid);
        ListNode l2 = merge(lists, mid + 1, hi);
        return merge2Lists(l1, l2);
    }
}

146. LRU caching mechanism

[medium] [Topic description] design and implement an LRU (least recently used) caching mechanism using the data structure you have mastered  
Implement LRUCache class:
LRUCache(int capacity) takes a positive integer as the capacity   Capacity initialize LRU cache
int get(int key) if the keyword key exists in the cache, the value of the keyword is returned; otherwise, - 1 is returned.
void put(int key, int value)   If the keyword already exists, change its data value; If the keyword does not exist, insert the group keyword value. When the cache capacity reaches the maximum, it should delete the longest unused data value before writing new data, so as to make room for new data values.
Advanced: can you   O(1) time complexity to complete these two operations?
Example: input:
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
Output: [null, null, null, 1, null, -1, null, -1, 3, 4]
Explanation:
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // Cache is {1 = 1}
lRUCache.put(2, 2); // Cache is {1 = 1, 2 = 2}
lRUCache.get(1);    // Return 1
lRUCache.put(3, 3); // This operation will invalidate keyword 2. The cache is {1 = 1, 3 = 3}
lRUCache.get(2);    // Return - 1 (not found)
lRUCache.put(4, 4); // This operation will invalidate keyword 1, and the cache is {4 = 4, 3 = 3}
lRUCache.get(1);    // Return - 1 (not found)
lRUCache.get(3);    // Return 3
lRUCache.get(4);    // Return 4

[simulation method] diagram:

public class LRUCache {
    class DLinkedNode {
        int key;
        int value;
        DLinkedNode prev;
        DLinkedNode next;
        public DLinkedNode() {}
        public DLinkedNode(int _key, int _value) {key = _key; value = _value;}
    }

    private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();
    private int size;
    private int capacity;
    private DLinkedNode head, tail;

    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        // Using pseudo header and pseudo tail nodes
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.prev = head;
    }

    public int get(int key) {
        DLinkedNode node = cache.get(key);
        if (node == null) {
            return -1;
        }
        // If the key exists, first locate it through the hash table, and then move it to the header
        moveToHead(node);
        return node.value;
    }

    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);
        if (node == null) {
            // If the key does not exist, create a new node
            DLinkedNode newNode = new DLinkedNode(key, value);
            // Add to hash table
            cache.put(key, newNode);
            // Add to the header of a two-way linked list
            addToHead(newNode);
            ++size;
            if (size > capacity) {
                // If the capacity is exceeded, delete the tail node of the two-way linked list
                DLinkedNode tail = removeTail();
                // Delete the corresponding entry in the hash table
                cache.remove(tail.key);
                --size;
            }
        }
        else {
            // If the key exists, first locate it through the hash table, then modify the value and move it to the header
            node.value = value;
            moveToHead(node);
        }
    }

    private void addToHead(DLinkedNode node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    private void removeNode(DLinkedNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void moveToHead(DLinkedNode node) {
        removeNode(node);
        addToHead(node);
    }

    private DLinkedNode removeTail() {
        DLinkedNode res = tail.prev;
        removeNode(res);
        return res;
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

Tags: data structure

Posted on Thu, 23 Sep 2021 18:34:04 -0400 by Jon12345