class035 数据结构设计高频题【算法】
算法讲解035【必备】数据结构设计高频题
code1 设计有setAll功能的哈希表
// setAll功能的哈希表
// 测试链接 : https://www.nowcoder.com/practice/7c4559f138e74ceb9ba57d76fd169967
// 请同学们务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
// 提交以下的code,提交时请把类名改成"Main",可以直接通过
思路:带时间戳
package class035;
// setAll功能的哈希表
// 测试链接 : https://www.nowcoder.com/practice/7c4559f138e74ceb9ba57d76fd169967
// 请同学们务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
// 提交以下的code,提交时请把类名改成"Main",可以直接通过
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.HashMap;
public class Code01_SetAllHashMap {
public static HashMap<Integer, int[]> map = new HashMap<>();
public static int setAllValue;
public static int setAllTime;
public static int cnt;
public static void put(int k, int v) {
if (map.containsKey(k)) {
int[] value = map.get(k);
value[0] = v;
value[1] = cnt++;
} else {
map.put(k, new int[] { v, cnt++ });
}
}
public static void setAll(int v) {
setAllValue = v;
setAllTime = cnt++;
}
public static int get(int k) {
if (!map.containsKey(k)) {
return -1;
}
int[] value = map.get(k);
if (value[1] > setAllTime) {
return value[0];
} else {
return setAllValue;
}
}
public static int n, op, a, b;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
map.clear();
setAllValue = 0;
setAllTime = -1;
cnt = 0;
n = (int) in.nval;
for (int i = 0; i < n; i++) {
in.nextToken();
op = (int) in.nval;
if (op == 1) {
in.nextToken();
a = (int) in.nval;
in.nextToken();
b = (int) in.nval;
put(a, b);
} else if (op == 2) {
in.nextToken();
a = (int) in.nval;
out.println(get(a));
} else {
in.nextToken();
a = (int) in.nval;
setAll(a);
}
}
}
out.flush();
out.close();
br.close();
}
}
code2 146. LRU 缓存
// 实现LRU结构
// 测试链接 : https://leetcode.cn/problems/lru-cache/
思路:HashMap+双向链表(新增结点到尾部,删除头部的结点,将结点移到尾部)
package class035;
import java.util.HashMap;
// 实现LRU结构
public class Code02_LRU {
// 测试链接 : https://leetcode.cn/problems/lru-cache/
class LRUCache {
class DoubleNode {
public int key;
public int val;
public DoubleNode last;
public DoubleNode next;
public DoubleNode(int k, int v) {
key = k;
val = v;
}
}
class DoubleList {
private DoubleNode head;
private DoubleNode tail;
public DoubleList() {
head = null;
tail = null;
}
public void addNode(DoubleNode newNode) {
if (newNode == null) {
return;
}
if (head == null) {
head = newNode;
tail = newNode;
} else {
tail.next = newNode;
newNode.last = tail;
tail = newNode;
}
}
public void moveNodeToTail(DoubleNode node) {
if (tail == node) {
return;
}
if (head == node) {
head = node.next;
head.last = null;
} else {
node.last.next = node.next;
node.next.last = node.last;
}
node.last = tail;
node.next = null;
tail.next = node;
tail = node;
}
public DoubleNode removeHead() {
if (head == null) {
return null;
}
DoubleNode ans = head;
if (head == tail) {
head = null;
tail = null;
} else {
head = ans.next;
ans.next = null;
head.last = null;
}
return ans;
}
}
private HashMap<Integer, DoubleNode> keyNodeMap;
private DoubleList nodeList;
private final int capacity;
public LRUCache(int cap) {
keyNodeMap = new HashMap<>();
nodeList = new DoubleList();
capacity = cap;
}
public int get(int key) {
if (keyNodeMap.containsKey(key)) {
DoubleNode ans = keyNodeMap.get(key);
nodeList.moveNodeToTail(ans);
return ans.val;
}
return -1;
}
public void put(int key, int value) {
if (keyNodeMap.containsKey(key)) {
DoubleNode node = keyNodeMap.get(key);
node.val = value;
nodeList.moveNodeToTail(node);
} else {
if (keyNodeMap.size() == capacity) {
keyNodeMap.remove(nodeList.removeHead().key);
}
DoubleNode newNode = new DoubleNode(key, value);
keyNodeMap.put(key, newNode);
nodeList.addNode(newNode);
}
}
}
}
code3 380. O(1) 时间插入、删除和获取随机元素
// 插入、删除和获取随机元素O(1)时间的结构
// 测试链接 : https://leetcode.cn/problems/insert-delete-getrandom-o1/
思路:HashMap+动态数组 remove()方法使用最后一个元素填补中间的空缺
package class035;
import java.util.ArrayList;
import java.util.HashMap;
// 插入、删除和获取随机元素O(1)时间的结构
public class Code03_InsertDeleteRandom {
// 测试链接 : https://leetcode.cn/problems/insert-delete-getrandom-o1/
class RandomizedSet {
public HashMap<Integer, Integer> map;
public ArrayList<Integer> arr;
public RandomizedSet() {
map = new HashMap<>();
arr = new ArrayList<>();
}
public boolean insert(int val) {
if (map.containsKey(val)) {
return false;
}
map.put(val, arr.size());
arr.add(val);
return true;
}
public boolean remove(int val) {
if (!map.containsKey(val)) {
return false;
}
int valIndex = map.get(val);
int endValue = arr.get(arr.size() - 1);
map.put(endValue, valIndex);
arr.set(valIndex, endValue);
map.remove(val);
arr.remove(arr.size() - 1);
return true;
}
public int getRandom() {
return arr.get((int) (Math.random() * arr.size()));
}
}
}
code4 381. O(1) 时间插入、删除和获取随机元素 - 允许重复
// 插入、删除和获取随机元素O(1)时间且允许有重复数字的结构
// 测试链接 :
// https://leetcode.cn/problems/insert-delete-getrandom-o1-duplicates-allowed/
思路:HashMap<Integer,HashSet< Integer>>+动态数组 remove()方法使用最后一个元素填补中间的空缺
package class035;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
// 插入、删除和获取随机元素O(1)时间且允许有重复数字的结构
public class Code04_InsertDeleteRandomDuplicatesAllowed {
// 测试链接 :
// https://leetcode.cn/problems/insert-delete-getrandom-o1-duplicates-allowed/
class RandomizedCollection {
public HashMap<Integer, HashSet<Integer>> map;
public ArrayList<Integer> arr;
public RandomizedCollection() {
map = new HashMap<>();
arr = new ArrayList<>();
}
public boolean insert(int val) {
arr.add(val);
HashSet<Integer> set = map.getOrDefault(val, new HashSet<Integer>());
set.add(arr.size() - 1);
map.put(val, set);
return set.size() == 1;
}
public boolean remove(int val) {
if (!map.containsKey(val)) {
return false;
}
HashSet<Integer> valSet = map.get(val);
int valAnyIndex = valSet.iterator().next();
int endValue = arr.get(arr.size() - 1);
if (val == endValue) {
valSet.remove(arr.size() - 1);
} else {
HashSet<Integer> endValueSet = map.get(endValue);
endValueSet.add(valAnyIndex);
arr.set(valAnyIndex, endValue);
endValueSet.remove(arr.size() - 1);
valSet.remove(valAnyIndex);
}
arr.remove(arr.size() - 1);
if (valSet.isEmpty()) {
map.remove(val);
}
return true;
}
public int getRandom() {
return arr.get((int) (Math.random() * arr.size()));
}
}
}
code5 295. 数据流的中位数
// 快速获得数据流的中位数的结构
// 测试链接 : https://leetcode.cn/problems/find-median-from-data-stream/
思路:大根堆+小根堆
package class035;
import java.util.PriorityQueue;
// 快速获得数据流的中位数的结构
public class Code05_MedianFinder {
// 测试链接 : https://leetcode.cn/problems/find-median-from-data-stream/
class MedianFinder {
private PriorityQueue<Integer> maxHeap;
private PriorityQueue<Integer> minHeap;
public MedianFinder() {
maxHeap = new PriorityQueue<>((a, b) -> b - a);
minHeap = new PriorityQueue<>((a, b) -> a - b);
}
public void addNum(int num) {
if (maxHeap.isEmpty() || maxHeap.peek() >= num) {
maxHeap.add(num);
} else {
minHeap.add(num);
}
balance();
}
public double findMedian() {
if (maxHeap.size() == minHeap.size()) {
return (double) (maxHeap.peek() + minHeap.peek()) / 2;
} else {
return maxHeap.size() > minHeap.size() ? maxHeap.peek() : minHeap.peek();
}
}
private void balance() {
if (Math.abs(maxHeap.size() - minHeap.size()) == 2) {
if (maxHeap.size() > minHeap.size()) {
minHeap.add(maxHeap.poll());
} else {
maxHeap.add(minHeap.poll());
}
}
}
}
}
code6 895. 最大频率栈
// 最大频率栈
// 测试链接 : https://leetcode.cn/problems/maximum-frequency-stack/
思路:多级链表+HashMap
package class035;
import java.util.ArrayList;
import java.util.HashMap;
// 最大频率栈
public class Code06_MaximumFrequencyStack {
// 测试链接 : https://leetcode.cn/problems/maximum-frequency-stack/
class FreqStack {
// 出现的最大次数
private int topTimes;
// 每层节点
private HashMap<Integer, ArrayList<Integer>> cntValues = new HashMap<>();
// 每一个数出现了几次
private HashMap<Integer, Integer> valueTimes = new HashMap<>();
public void push(int val) {
valueTimes.put(val, valueTimes.getOrDefault(val, 0) + 1);
int curTopTimes = valueTimes.get(val);
if (!cntValues.containsKey(curTopTimes)) {
cntValues.put(curTopTimes, new ArrayList<>());
}
ArrayList<Integer> curTimeValues = cntValues.get(curTopTimes);
curTimeValues.add(val);
topTimes = Math.max(topTimes, curTopTimes);
}
public int pop() {
ArrayList<Integer> topTimeValues = cntValues.get(topTimes);
int ans = topTimeValues.remove(topTimeValues.size() - 1);
if (topTimeValues.size() == 0) {
cntValues.remove(topTimes--);
}
int times = valueTimes.get(ans);
if (times == 1) {
valueTimes.remove(ans);
} else {
valueTimes.put(ans, times - 1);
}
return ans;
}
}
}
code7 432. 全 O(1) 的数据结构
// 全O(1)的数据结构
// 测试链接 : https://leetcode.cn/problems/all-oone-data-structure/
思路:HashMap+双向链表
package class035;
import java.util.HashMap;
import java.util.HashSet;
// 全O(1)的数据结构
public class Code07_AllO1 {
// 测试链接 : https://leetcode.cn/problems/all-oone-data-structure/
class AllOne {
class Bucket {
public HashSet<String> set;
public int cnt;
public Bucket last;
public Bucket next;
public Bucket(String s, int c) {
set = new HashSet<>();
set.add(s);
cnt = c;
}
}
private void insert(Bucket cur, Bucket pos) {
cur.next.last = pos;
pos.next = cur.next;
cur.next = pos;
pos.last = cur;
}
private void remove(Bucket cur) {
cur.last.next = cur.next;
cur.next.last = cur.last;
}
Bucket head;
Bucket tail;
HashMap<String, Bucket> map;
public AllOne() {
head = new Bucket("", 0);
tail = new Bucket("", Integer.MAX_VALUE);
head.next = tail;
tail.last = head;
map = new HashMap<>();
}
public void inc(String key) {
if (!map.containsKey(key)) {
if (head.next.cnt == 1) {
map.put(key, head.next);
head.next.set.add(key);
} else {
Bucket newBucket = new Bucket(key, 1);
map.put(key, newBucket);
insert(head, newBucket);
}
} else {
Bucket bucket = map.get(key);
if (bucket.next.cnt == bucket.cnt + 1) {
map.put(key, bucket.next);
bucket.next.set.add(key);
} else {
Bucket newBucket = new Bucket(key, bucket.cnt + 1);
map.put(key, newBucket);
insert(bucket, newBucket);
}
bucket.set.remove(key);
if (bucket.set.isEmpty()) {
remove(bucket);
}
}
}
public void dec(String key) {
Bucket bucket = map.get(key);
if (bucket.cnt == 1) {
map.remove(key);
} else {
if (bucket.last.cnt == bucket.cnt - 1) {
map.put(key, bucket.last);
bucket.last.set.add(key);
} else {
Bucket newBucket = new Bucket(key, bucket.cnt - 1);
map.put(key, newBucket);
insert(bucket.last, newBucket);
}
}
bucket.set.remove(key);
if (bucket.set.isEmpty()) {
remove(bucket);
}
}
public String getMaxKey() {
return tail.last.set.iterator().next();
}
public String getMinKey() {
return head.next.set.iterator().next();
}
}
}