vivo智能手机产能
https://www.nowcoder.com/questionTerminal/2e4363c23c6741f98319d5a7e3882325?toCommentId=14113374
import java.util.*;
public class Solution {
public int solution (int n) {
int afterDay = 1; //接下来的1,2,3,4天
int i = 0; //第几天--也可以从1开始,不过需要修改条件<=n, i== n+1
int sum = 0;
while(i < n) {
//接下来的afterDay天内,产量都是afterDay
for(int j = 1; j <= afterDay; j++) {
sum+=afterDay;
i++;
if(i == n) return sum;
}
afterDay+=1;
}
return sum;
}
}
146. LRU 缓存
缓存,意味着某些元素到了一定条件就会被清除,而对于被重复使用的元素则会被保存更久。
力扣:https://leetcode.cn/problems/lru-cache/
思路:哈希表+双向链表
LRU缓存需要两个操作,一个是get操作,一个是put操作,由于get和put要达到O(1)级别,所以只有用哈希表存放才能实现。LRU缓存还要求那些不常用的元素要被移除(条件是当缓存超过指定大小),这就需要实现双向链表了。put的时候,如果超过大小,需要先移除不常用元素才能添加,不常用的元素可通过头节点移除,在通过尾节点添加新元素。对于get访问过的节点,只需要移到链表尾部即可,这样就能保证其活得更久。其中移除只有使用双链表才能使速度达到O(1)级别,因为链表移除一个非头部或尾部的节点需要前一个节点的协助。只有双向链表能根据一个节点移除该节点
class LRUCache {
class Node { //有前后指针的节点
Node prev; //指向上一个
Node next; //指向下一个
Integer value;
Integer key;
public Node() {
}
public Node(Integer key, Integer value) {
this.key = key;
this.value = value;
}
}
Map<Integer, Node> map = null; //存放key和node
int capacity;
Node head; //头节点---------用于移除最近最少使用的元素
Node tail; //尾节点---------用于添加元素
public LRUCache(int capacity) {
map = new HashMap<>(capacity);
this.capacity = capacity;
//初始化双向链表
head = new Node();
tail = new Node();
head.next = tail;
tail.prev = head;
}
public int get(int key) {
if (!map.containsKey(key)) return -1;
//将该节点移到链表尾部==移除+添加
Node node = map.get(key);
remove(node);
insert(node);
return node.value;
}
public void put(Integer key, Integer value) {
//存在则更新
if(map.containsKey(key)) {
Node node = map.get(key);
remove(node);
node.value = value;
insert(node);
return;
}
//超过缓存大小
if(map.size() == this.capacity) {
//head.next代表链表的第二个节点,也就是不常用的节点
//先删除map中的键值;然后移除节点,顺序不可颠倒,因为先移除head.next会改变。
map.remove(head.next.key);
remove(head.next);
}
Node node = new Node(key, value);
map.put(key, node);
insert(node);
}
//根据节点移除该节点
public void remove(Node node) {
node.prev.next = node.next;
node.next.prev = node.prev;
node.prev = null;
node.next = null;
}
//将元素添加到尾节点
public void insert(Node node) {
tail.prev.next = node; //倒数第二个节点指向node
node.prev = tail.prev; //node指向倒数第二个节点
tail.prev = node; //尾节点执行node
node.next = tail; //node指向尾节点
}
}
测试用例
["LRUCache","get","put","get","put","put","get","get"]
[[2],[2],[2,6],[1],[1,5],[1,2],[1],[2]]
["LRUCache","put","put","put","put","get","get"]
[[2],[2,1],[1,1],[2,3],[4,1],[1],[2]]
*滑动窗口最大值
链接:https://leetcode.cn/problems/sliding-window-maximum/
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
//双端队列
LinkedList<Integer> queue = new LinkedList<>();
//预处理前三个元素----可以合并到下面,当i>=k时,执行res
for(int i = 0 ; i < k; i++) {
while(!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) {
queue.pollLast();
}
queue.add(i);
}
int l = nums.length;
int[] res = new int[l - k + 1];
int c = 0;
for(int i = k; i < l; i++) {
res[c++] = nums[queue.peek()];
//保证队列单调递减
while(!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) {
queue.pollLast();
}
queue.add(i);
//判断是否需要移除队头元素,如果该位置在滑动窗口左边就要移除
if(queue.peek() <= i - k) {
queue.poll();
}
}
res[c++] = nums[queue.peek()];
return res;
}
}