Data Structure and Algorithm - Day 13 - Course End

  • LRU Cache (least recently used)

    multi-level cache in CPU

    image-20210322081926011

    LRU: Hash Table + Double Linked List

    image-20210322082414832

    Time complexity: O(1) lookup, O(1) update/modify

    其他缓存替换方法

  • 146. LRU Cache

    Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.

    Implement the LRUCache class:

    • LRUCache(int capacity) Initialize the LRU cache with positive size capacity.
    • int get(int key) Return the value of the key if the key exists, otherwise return -1.
    • void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.

    Follow up:
    Could you do get and put in O(1) time complexity?

    Example 1:

    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); // LRU key was 2, evicts key 2, cache is {1=1, 3=3}
    lRUCache.get(2);    // returns -1 (not found)
    lRUCache.put(4, 4); // LRU key was 1, evicts key 1, cache is {4=4, 3=3}
    lRUCache.get(1);    // return -1 (not found)
    lRUCache.get(3);    // return 3
    lRUCache.get(4);    // return 4
    

    Constraints:

    • 1 <= capacity <= 3000
    • 0 <= key <= 3000
    • 0 <= value <= 104
    • At most 3 * 104 calls will be made to get and put.
    class LRUCache {
        class DLinkedNode {
            int key;
            int value;
            DLinkedNode pre;
            DLinkedNode next;
            public DLinkedNode () {
                
            }
            public DLinkedNode (int key, int value) {
                this.key = key;
                this.value = value;
            }
        }
        
        private Map<Integer, DLinkedNode> cache = new HashMap<>();
        private int size;
        private int cap;
        private DLinkedNode head, tail;
    
        public LRUCache(int capacity) {
            this.size = 0;
            this.cap = capacity;
            head = new DLinkedNode();
            tail = new DLinkedNode();
            head.next = tail;
            tail.pre = head;
        }
    
        public int get(int key) {
            DLinkedNode node = cache.get(key);
            if (node == null) {
                return -1;
            }
            moveToHead(node);
            return node.value;
        }
    
        public void put(int key, int value) {
            DLinkedNode node = cache.get(key);
            if (node == null) {
                DLinkedNode newNode = new DLinkedNode(key, value);
                cache.put(key, newNode);
                addToHead(newNode);
                size++;
                if (size > cap) {
                    DLinkedNode tail = removeTail();
                    cache.remove(tail.key);
                    size--;
                }
            } else {
                node.value = value;
                moveToHead(node);
            }
        }
    
        private void moveToHead(DLinkedNode node) {
            removeNode(node);
            addToHead(node);
        }
    
        private void removeNode(DLinkedNode node) {
            node.pre.next = node.next;
            node.next.pre = node.pre;
        }
    
        private void addToHead(DLinkedNode node) {
            node.pre = head;
            node.next = head.next;
            head.next.pre = node;
            head.next = node;
        }
    
        private DLinkedNode removeTail() {
            DLinkedNode res = tail.pre;
            removeNode(res);
            return res;
        }
    }
    
  • Bloom Filter

    套在外层的缓存!

    一个很长的二进制向量和一系列随机映射函数。

    布隆过滤器可以用于检索一个元素是否在一个集合中。

    优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

    image-20210322080759635

    只要有一个映射位是0,元素一定不存在;映射位都是1也不一定存在,存在误差。

    案例:

    1. 比特币网络
    2. 分布式系统(Map-Reduce) - Hadoop、search engine
    3. Redis缓存
    4. 垃圾邮件、评论等的过滤

    Java 实现:示例 1 示例 2

  • Sort

    image-20210322090858421

    image-20210322090927281

    重点:堆排序,快速排序,归并排序

    归并:先排序左右子数组,然后合并两个有序子数组
    快排:先调配出左右子数组,然后对于左右子数组进行排序

  • 1122. Relative Sort Array

    Given two arrays arr1 and arr2, the elements of arr2 are distinct, and all elements in arr2 are also in arr1.

    Sort the elements of arr1 such that the relative ordering of items in arr1 are the same as in arr2. Elements that don't appear in arr2 should be placed at the end of arr1 in ascending order.

    Example 1:

    Input: arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6]
    Output: [2,2,2,1,4,3,3,9,6,7,19]
    

    Constraints:

    • 1 <= arr1.length, arr2.length <= 1000
    • 0 <= arr1[i], arr2[i] <= 1000
    • All the elements of arr2 are distinct.
    • Each arr2[i] is in arr1.
    class Solution {
        public int[] relativeSortArray(int[] arr1, int[] arr2) {
            int i = 0;
            for (int i2 = 0; i2 < arr2.length; i2++) {
                for (int i1 = 0; i1 < arr1.length; i1++) {
                    if (arr1[i1] == arr2[i2]) {
                        int t = arr1[i];
                        arr1[i++] = arr1[i1];
                        arr1[i1] = t;
                    }
                }
            }
            Arrays.sort(arr1, i, arr1.length);
            return arr1;
        }
    }
    
  • 56. Merge Intervals

    Given an array of intervals where intervals[i] = [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.

    Example 1:

    Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
    Output: [[1,6],[8,10],[15,18]]
    Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].
    

    Example 2:

    Input: intervals = [[1,4],[4,5]]
    Output: [[1,5]]
    Explanation: Intervals [1,4] and [4,5] are considered overlapping.
    

    Constraints:

    • 1 <= intervals.length <= 104
    • intervals[i].length == 2
    • 0 <= starti <= endi <= 104
    class Solution {
        public int[][] merge(int[][] intervals) {
            Deque<int[]> deque = new LinkedList<>();
            Arrays.sort(intervals, (x,y)->(x[1]-y[1]));
            Arrays.sort(intervals, (x,y)->(x[0]-y[0]));
            for (int[] interval : intervals) {
                if (deque.isEmpty()) {
                    deque.addLast(interval);
                    continue;
                }
                int end = deque.peekLast()[1];
                if (interval[0] <= end) {
                    deque.peekLast()[1] = Math.max(end, interval[1]);
                } else {
                    deque.addLast(interval);
                }
            }
            int n = deque.size();
            int[][] res = new int[n][2];
            for (int i = 0; i < n; i++) {
                res[i] = deque.pollFirst();
            }
            return res;
        }
    }
    
  • 493. Reverse Pairs

    Given an array nums, we call (i, j) an *important reverse pair* if i < j and nums[i] > 2*nums[j].

    You need to return the number of important reverse pairs in the given array.

    Example1:

    Input: [1,3,2,3,1]
    Output: 2
    

    Example2:

    Input: [2,4,3,5,1]
    Output: 3
    

    Note:

    1. The length of the given array will not exceed 50,000.
    2. All the numbers in the input array are in the range of 32-bit integer.
    class Solution {
        int res = 0;
        public int reversePairs(int[] nums) {
            mergeSort(nums, 0, nums.length - 1);
            return res;
        }
    
        private void mergeSort(int[] nums, int left, int right) {
            if (right <= left) return ;
            int mid = (right - left) / 2 + left;
            mergeSort(nums, left, mid);
            mergeSort(nums, mid + 1, right);
            merge(nums, left, mid, right);
        }
    
        private void merge(int[] nums, int l1, int r1, int r2) {
            // count res
            int p = l1, q = r1 + 1;
            while (p <= r1 && q <= r2) {
                if (nums[p] > (long) nums[q] * 2) {
                    res += r1 - p + 1;
                    q++;
                } else p++;
            }
    
            int[] arr = new int[r2 - l1 + 1];
            int start = l1, i = 0, l2 = r1 + 1;
            while (l1 <= r1 && l2 <= r2) {
                arr[i++] = nums[l1] > nums[l2] ? nums[l2++] : nums[l1++];
            }
            while (l1 <= r1) arr[i++] = nums[l1++];
            while (l2 <= r2) arr[i++] = nums[l2++];
            for (l1 = start; l1 <= r2; l1++) {
                nums[l1] = arr[l1 - start];
            }
        }
    }
    
posted @ 2021-03-22 12:47  鹏懿如斯  阅读(47)  评论(0编辑  收藏  举报