LeetCode 1877. 数组中最大数对和的最小值/剑指 Offer 52. 两个链表的第一个公共节点/146. LRU 缓存机制

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 1877. 数组中最大数对和的最小值/剑指 Offer 52. 两个链表的第一个公共节点/146. LRU 缓存机制相关的知识,希望对你有一定的参考价值。

1877. 数组中最大数对和的最小值

2021.7.20 每日一题

题目描述

一个数对 (a,b) 的 数对和 等于 a + b 。最大数对和 是一个数对数组中最大的 数对和 。

比方说,如果我们有数对 (1,5) ,(2,3) 和 (4,4),最大数对和 为 max(1+5, 2+3, 4+4) = max(6, 5, 8) = 8 。

给你一个长度为 偶数 n 的数组 nums ,请你将 nums 中的元素分成 n / 2 个数对,使得:

nums 中每个元素 恰好 在 一个 数对中,且
最大数对和 的值 最小 。

请你在最优数对划分的方案下,返回最小的 最大数对和 。

示例 1:

输入:nums = [3,5,2,3]
输出:7
解释:数组中的元素可以分为数对 (3,3) 和 (5,2) 。
最大数对和为 max(3+3, 5+2) = max(6, 7) = 7 。

示例 2:

输入:nums = [3,5,4,2,4,6]
输出:8
解释:数组中的元素可以分为数对 (3,5),(4,4) 和 (6,2) 。
最大数对和为 max(3+5, 4+4, 6+2) = max(8, 8, 8) = 8 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimize-maximum-pair-sum-in-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

第二次参加周赛的第二题,最大最小匹配就可以了

class Solution {
    public int minPairSum(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        int max = 0;
        int l = 0;
        int r = n - 1;
        while(l < r){
            max = Math.max(max, nums[l] + nums[r]);
            l++;
            r--;
        }
        return max;
    }
}

剑指 Offer 52. 两个链表的第一个公共节点

2021.7.21 每日一题

题目描述

输入两个链表,找出它们的第一个公共节点。

如下面的两个链表:

在节点 c1 开始相交。

示例 1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

两个指针分别指向两个链表,然后一直走,走到头就指向另一个链表的头。
直到相遇或者同时为空
要么相守,要么灭亡,泪目!

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null){
            return null;
        }
        ListNode index1 = headA;
        ListNode index2 = headB;
        while(index1 != index2){
            index1 = index1.next;
            index2 = index2.next;
            if(index1 == null && index2 == null)
                return null;
            if(index1 == null){
                index1 = headB;
            }
            if(index2 == null)
                index2 = headA;
        }
        return index1;
    }
}

然后看了一下我之前写的代码,自己第一次遇到这个问题时,想到的做法是,两个指针同时指向末尾,然后再向前,直到不相同,就找到了第一个相同的节点。当然,麻烦了

另一个提交是这样的,还能这样简化一下上面的代码:
这个代码有什么启发呢,就是null可以和null相等,也就是null==null,返回的是true,要记住
但是不能大于和小于

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode currA = headA;
        ListNode currB = headB;
        while(currA != currB){
            currA = currA == null ? headB : currA.next;
            currB = currB == null ? headA : currB.next;
        }
        return currA;
    }
}

另外,在查这个点的过程中,发现null其他需要注意的:
1.不能用一个值为null的引用类型变量来调用非静态方法来使,它将会抛出空指针异常。但是你可能不知道,你可以使用静态方法来使用一个值为null的引用类型变量。因为静态方法使用静态绑定,不会抛出空指针异常。
2.如果使用了带有null值的引用类型变量,instanceof操作将会返回false

Integer iAmNull = null;
if(iAmNull instanceof Integer){ 
//if里面是false

3.字符串相加:null+null = nullnull
如果拼接的字符串中包含变量,则在编译时编译器采用StringBuilder对其进行优化,即自动创建StringBuilder实例并调用其append()方法,将这些字符串拼接在一起。

public class NullTest {
       public static void main(String[] args) {      
            String str1=null;        
            String str2=null;        
            String str3=str1+str2;      
            System.out.println(str3);  
       }
}

而StringBuilder源码中:

public AbstractStringBuilder append(String str) {    
        if (str == null) 
                str = "null";     
        int len = str.length();       
        ensureCapacityInternal(count + len);  
        str.getChars(0, len, value, count);  
        count += len;      
        return this;   
}

146. LRU 缓存机制

题目描述

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:

LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?

示例:

输入
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lru-cache
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

首先,看清这个实现功能是什么意思
就是只要是使用过了,就放在最新的位置,然后每次删除是删除最旧的
哈希表中存储key和node的位置,然后链表头部是旧的,尾部是新的,新加的节点放在尾部
代码中可以写两个方法,使代码复用一下,这里就不写了

class LRUCache {
    //看到这个题,想到的是Map+queue吧,然后又想了一下,好像有个LinkedHashMap就是这么个实现方法
    //刚刚没看明白这个题,我就说怎么一直不对
    //这个题要求是删除最久未使用的数据值,这样就得按照存储的先后顺序和使用的顺序存储
    class Node{
        Node next;
        Node pre;
        int key;
        int val;
        
        public Node(){}
        
        public Node(int key, int value){
            this.key = key;
            this.val = value;
        }
    }
    
    int capacity;
    Map<Integer, Node> map = new HashMap<>();
    //头节点和尾结点
    //尾部是新的, 头部是旧的
    Node first;
    Node last;
    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.first = new Node();
        this.last = new Node();
        first.next = last;
        last.pre = first;
    }
    
    public int get(int key) {
        //找到当前节点,移动到尾部
        if(map.containsKey(key)){
            Node temp = map.get(key);
            temp.pre.next = temp.next;
            temp.next.pre = temp.pre;
            last.pre.next = temp;
            temp.pre = last.pre;
            temp.next = last;
            last.pre = temp;
            return temp.val;
        }
        else
            return -1;

    }
    
    public void put(int key, int value) {
        if(map.containsKey(key)){
            Node temp = map.get(key);
            temp.val = value;
            temp.pre.next = temp.next;
            temp.next.pre = temp.pre;
            last.pre.next = temp;
            temp.pre = last.pre;
            temp.next = last;
            last.pre = temp;
            return;
        }
        int size = map.size();
        if(size == capacity){
            //先获得头部的key
            int del = first.next.key;
            map.remove(del);
            //去掉这个节点
            first.next = first.next.next;
            first.next.pre = first;
        }
        //加入这个节点
        Node node = new Node(key, value);
        map.put(key, node);
        last.pre.next = node;
        node.pre = last.pre;
        node.next = last;
        last.pre = node;
    }
}

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

官解给的直接继承LinkedHashMap的方法
LinkedHashMap可以按照插入顺序排序,也可以按照读取的顺序排序(也就是这个题),也就是LRU

class LRUCache extends LinkedHashMap<Integer, Integer>{
    private int capacity;
    
    public LRUCache(int capacity) {
        super(capacity, 0.75F, true);
        this.capacity = capacity;
    }

    public int get(int key) {
        return super.getOrDefault(key, -1);
    }

    public void put(int key, int value) {
        super.put(key, value);
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
        return size() > capacity; 
    }
}

补充:LRU缓存机制

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

以上是关于LeetCode 1877. 数组中最大数对和的最小值/剑指 Offer 52. 两个链表的第一个公共节点/146. LRU 缓存机制的主要内容,如果未能解决你的问题,请参考以下文章

算法1877. 数组中最大数对和的最小值(多语言实现)

算法1877. 数组中最大数对和的最小值(多语言实现)

1877. 数组中最大数对和的最小值

1877. 数组中最大数对和的最小值

文巾解题 1877. 数组中最大数对和的最小值

[M贪心] lc1877. 数组中最大数对和的最小值(贪心+双周赛53_2)