2022-5-24 笔试真题练习

手写LRU:

 1 import java.util.HashMap;
 2 import java.util.Map;
 3 
 4 public class LRUCache {
 5     Map<Integer,Node> map=new HashMap<>();
 6     Node head;
 7     Node tail;
 8     int size;
 9     int capacity;
10     static class Node{
11         int key,value;
12         Node prev,next;
13         Node(){
14         }
15         Node(int k,int v){
16             key=k;
17             value=v;
18         }
19     }
20 
21 
22 //    public  void getfirst(int key){
23 //        Node node=map.get(key);
24 //        removeKey(node);
25 //        addfirst(node);
26 //    }
27 
28     public void removeNode(Node node){
29         Node prev=node.prev;
30         Node next=node.next;
31         prev.next=next;
32         next.prev=prev;
33         map.remove(node.key);
34         size--;
35     }
36 
37     public void addNode(Node node){
38         head.next.prev=node;
39         node.next=head.next;
40         head.next=node;
41         node.prev=head;
42         map.put(node.key,node);
43         size++;
44     }
45     // prev->node->tail
46     // prev<-node<-tail
47 //    public void removeLast(){
48 //        Node node=tail.prev;
49 //        tail.prev=node.prev;
50 //        tail.prev.next=tail;
51 //        map.remove(node.key);
52 //        size--;
53 //    }
54     public LRUCache(int capacity) {
55         head=new Node();
56         tail=new Node();
57         head.next=tail;
58         tail.prev=head;
59         size=0;
60         this.capacity=capacity;
61     }
62 
63     public int get(int key) {
64         if (!map.containsKey(key)){
65             return -1;
66         }else{
67             // 提取当前key到最前面
68             Node node=map.get(key);
69             removeNode(node);
70             addNode(node);
71             return map.get(key).value;
72         }
73 
74     }
75 
76     public void put(int key, int value) {
77         if (map.containsKey(key)){
78             Node node=map.get(key);
79             node.value=value;
80             removeNode(node);
81             addNode(node);
82         }else{
83             Node node=new Node(key,value);
84             if (size==capacity) {
85                 removeNode(tail.prev);
86             }
87             addNode(node);
88         }
89     }
90 
91 
92 }

思路:map记录映射位置,双向链表记录顺序。

 

手写LFU:

  1 import java.util.HashMap;
  2 import java.util.Map;
  3 import java.util.PriorityQueue;
  4 
  5 public class LFUCache {
  6     Map<Integer,Node> keyToNode;
  7     Map<Integer,DoubleList> freqToList;
  8     int capacity,minFreq;
  9     public LFUCache(int capacity) {
 10         keyToNode=new HashMap<>();
 11         freqToList=new HashMap<>();
 12         this.capacity=capacity;
 13         minFreq=0;
 14     }
 15 
 16     public int get(int key) {
 17         if (keyToNode.size()==0||!keyToNode.containsKey(key)) return -1;
 18         // freq要加1 添加到freq+1的链表中 更新最小频率
 19         Node node= keyToNode.get(key);
 20         int freq=node.freq;
 21         freqToList.get(freq).deleteNode(node);
 22         DoubleList doubleList=freqToList.getOrDefault(++node.freq,new DoubleList());
 23         doubleList.addNode(node);
 24         freqToList.put(node.freq,doubleList);
 25         if (freqToList.getOrDefault(minFreq,new DoubleList()).size==0){
 26             minFreq++;
 27         }
 28         return node.value;
 29     }
 30 
 31     public void put(int key, int value) {
 32         if (!keyToNode.containsKey(key)){
 33             // 添加key的索引,对应的链表也要加, minfreq更新
 34             Node node=new Node(key,value,1);
 35             if (keyToNode.size()==capacity){
 36                 // 满了 先去掉一个
 37                 DoubleList doubleList=freqToList.get(minFreq);
 38                 Node needDelete=doubleList.head.next;
 39                 keyToNode.remove(needDelete.key);
 40                 doubleList.deleteNode(doubleList.head.next);
 41             }
 42             keyToNode.put(key,node);
 43             DoubleList doubleList=freqToList.getOrDefault(1,new DoubleList());
 44             doubleList.addNode(node);
 45             freqToList.put(1,doubleList);
 46             // 必定为1
 47             minFreq=1;
 48         }else{
 49             // 取出
 50             // 从freq中删掉,加入到freq+1中 更新minfreq
 51             Node node=keyToNode.get(key);
 52             freqToList.get(node.freq).deleteNode(node);
 53             DoubleList doubleList=freqToList.getOrDefault(++node.freq,new DoubleList());
 54             doubleList.addNode(node);
 55             freqToList.put(node.freq,doubleList);
 56             if (freqToList.getOrDefault(minFreq,new DoubleList()).size==0){
 57                 minFreq++;
 58             }
 59             node.value=value;
 60         }
 61     }
 62 }
 63 
 64 class Node{
 65     int key,value,freq;
 66     Node prev,next;
 67     Node(){
 68 
 69     }
 70     Node(int k,int v,int f){
 71         key=k;
 72         value=v;
 73         freq=f;
 74     }
 75 }
 76 
 77 class DoubleList{
 78     int size;
 79     Node head,tail;
 80     DoubleList(){
 81         head=new Node();
 82         tail=new Node();
 83         head.next=tail;
 84         tail.prev=head;
 85         size=0;
 86     }
 87     //尾部加入
 88     public void addNode(Node node){
 89         tail.prev.next=node;
 90         node.prev=tail.prev;
 91         node.next=tail;
 92         tail.prev=node;
 93         size++;
 94     }
 95     //删除节点,一般从头部删除
 96     public void deleteNode(Node node){
 97         Node prev=node.prev;
 98         Node next=node.next;
 99         prev.next=next;
100         next.prev=prev;
101         size--;
102     }
103 
104 }

思路:双哈希表,一个表记录位置,一个表记录频率对应的双向链表。

 

 1 import java.util.*;
 2 
 3 public class LFUCache2 {
 4     Map<Integer,NewNode> map;
 5     TreeSet<NewNode> set;
 6     int capacity,time;
 7     public LFUCache2(int capacity) {
 8         map=new HashMap<>();
 9         set=new TreeSet<>();
10         this.capacity=capacity;
11         time=0;
12     }
13 
14     public int get(int key) {
15         if (capacity==0||!map.containsKey(key)) return -1;
16         NewNode node=map.get(key);
17         map.remove(key);
18         set.remove(node);
19         node.freq++;
20         node.time=++time;
21         map.put(key,node);
22         set.add(node);
23         return node.value;
24     }
25 
26     public void put(int key, int value) {
27         if (capacity==0) return;
28         if (!map.containsKey(key)){
29             // 新增
30             if (capacity<=set.size()){
31                 NewNode node = set.first();
32                 map.remove(node.key);
33                 NewNode newnode=new NewNode(key,value,++time,1);
34                 set.remove(node);
35                 map.put(key,newnode);
36                 set.add(newnode);
37             }else{
38                 NewNode newnode=new NewNode(key,value,++time,1);
39                 set.add(newnode);
40                 map.put(key,newnode);
41             }
42         }else{
43             // 更新
44             NewNode node = map.get(key);
45             map.remove(key);
46             set.remove(node);
47             node.freq++;
48             node.time=++time;
49             node.value=value;
50             map.put(key,node);
51             set.add(node);
52         }
53     }
54 
55     public static void main(String[] args) {
56         LFUCache2 lfu = new LFUCache2(2);
57         lfu.put(2, 1);   // cache=[1,_], cnt(1)=1
58         lfu.put(3, 2);   // cache=[2,1], cnt(2)=1, cnt(1)=1
59         System.out.println(lfu.get(3));
60         // cache=[1,2], cnt(2)=1, cnt(1)=2
61         //lfu.put(3, 3);   // 去除键 2 ,因为 cnt(2)=1 ,使用计数最小
62         // cache=[3,1], cnt(3)=1, cnt(1)=2
63         System.out.println(lfu.get(2));
64         //System.out.println(lfu.get(3));
65         // cache=[3,1], cnt(3)=2, cnt(1)=2
66         lfu.put(4, 3);   // 去除键 1 ,1 和 3 的 cnt 相同,但 1 最久未使用
67         // cache=[4,3], cnt(4)=1, cnt(3)=2
68         System.out.println(lfu.get(2));
69         System.out.println(lfu.get(3));
70         // cache=[3,4], cnt(4)=1, cnt(3)=3
71         System.out.println(lfu.get(4));
72     }
73 }
74 
75 class NewNode implements Comparable<NewNode> {
76     int key,value,time,freq;
77     NewNode(){
78 
79     }
80     NewNode(int k,int v,int t,int f){
81         key=k;
82         value=v;
83         time=t;
84         freq=f;
85     }
86 
87     @Override
88     public int compareTo(NewNode o) {
89         return this.freq==o.freq?this.time-o.time:this.freq-o.freq;
90     }
91 }

思路:treeset 集合去重并且根据频率和时间排序。

 

多多的魔术盒子

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 256M,其他语言512M

多多鸡有N个魔术盒子(编号1~N),其中编号为i的盒子里有i个球。
多多鸡让皮皮虾每次选择一个数字X(1 <= X <= N),多多鸡就会把球数量大于等于X个的盒子里的球减少X个。
通过观察,皮皮虾已经掌握了其中的奥秘,并且发现只要通过一定的操作顺序,可以用最少的次数将所有盒子里的球变没。
那么请问聪明的你,是否已经知道了应该如何操作呢?
 


输入描述:
第一行,有1个整数T,表示测试用例的组数。
(1 <= T <= 100)
接下来T行,每行1个整数N,表示有N个魔术盒子。
(1 <= N <= 1,000,000,000)

输出描述:
共T行,每行1个整数,表示要将所有盒子的球变没,最少需要进行多少次操作。

 1 //5 1 2 3 4 5
 2 // 1 2 0 1 2
 3 // 2N+1 1 2 3 4 N 2N+1
 4 // 1 2 3 4 N-1 0 N-1 N 4 3 2 1
 5 // f(2*n+1)=f(n-1)+1
 6 // 1 2 3 4 5 N .. 2N
 7 // 1 2 3 4 5 N-1 0 1 2 N-1 N
 8 // f(2*n)=max
 9 // 1 2 3 4 5 6
10 // 1 2 0 1 2 3
11 // 1 0 0 1 0 1
12 import java.util.*;
13 public class Main{
14     public static void main(String[] args) {
15         Scanner sc=new Scanner(System.in);
16         int n=sc.nextInt();
17         for (int i=0;i<n;i++){
18             System.out.println(f(sc.nextInt()));
19         }
20     }
21     public static int f(int x){
22         if (x==1) return 1;
23         else if (x%2==0) return f(x/2)+1;
24         else return f((x-1)/2)+1;
25     }
26 }

思路:递归公式,

/**
* f(2n)=f(n)+1
* f(2*n+1)=f(n)+1
* n=1 1
* n=2 2
* n=3 2
* n=4 3
* n=5 f(3)+1 f(3)=f(2)+1 f(2)=2;
* // 1 2 3... n ... 2n-1
* 1 2 3 4..n-1.0 1 2 ...n-1
* 1 2 3 4 5
* 1 2 0 1 2
* 0 1 0 1 0
*
*/

多多的排列函数

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 256M,其他语言512M

数列 {An} 为N的一种排列。
例如N=3,可能的排列共6种:
 
1
2
3
4
5
6
1, 2, 3
1, 3, 2
2, 1, 3
2, 3, 1
3, 1, 2
3, 2, 1
定义函数F:
其中|X|表示X的绝对值。
 
现在多多鸡想知道,在所有可能的数列 {An} 中,F(N)的最小值和最大值分别是多少。

输入描述:
第一行输入1个整数T,表示测试用例的组数。
( 1 <= T <= 10 )
第二行开始,共T行,每行包含1个整数N,表示数列 {An} 的元素个数。
( 1 <= N <= 100,000 )

输出描述:
共T行,每行2个整数,分别表示F(N)最小值和最大值
 1 import java.util.*;
 2 public class Main{
 3     public static void main(String[] args) {
 4         Scanner sc=new Scanner(System.in);
 5         int n=sc.nextInt();
 6         for (int i=0;i<n;i++){
 7             int num=sc.nextInt();
 8             int min=(num%4==0||num%4==3)?0:1;
 9             num--;
10             int max=(num%4==0||num%4==3)?num+1:num;
11             System.out.println(min+" "+max);
12         }
13     }
14 }

思路:找规律。n,n-1,n-2,n-3必定可以使最小值变为0,所以每四个一组可以抵消最小值的计算。所以按照4的余数分类。

而最大值可以根据上一组排列的最小值计算得出。

/**
* 4n+3 最小值为0
* 4n+2 最小值为1
* 4n+1 最小值为1
* 4n 最小值也为0
* 偶数
* 1 4 2 3
* min<=f(n-1)<=max
* n-max<=f(n)<=n-min
* max(n)=n-min(n-1)
* min 1 1 0 0 1 1
* max 1 1 2 4 5 5
*/
 

posted on 2022-05-24 23:15  阿ming  阅读(21)  评论(0编辑  收藏  举报

导航