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 缓存机制的主要内容,如果未能解决你的问题,请参考以下文章