刷题笔记系列
【刷题笔记01】- 数组
【刷题笔记02】-链表
【刷题笔记03 -哈希表】
1、用栈实现队列
- 思路:
栈是先进后出,队列是先进先出,也就是说相同的顺序进入,出来结果是反的。
用栈实现队列那势必需要像交换值一样,有个中间容器暂存数据。
用两个栈实现队列,一个管理入栈,一个管理出栈。 - 代码
class MyQueue {
Stack<Integer> stackIn;
Stack<Integer> stackOut;
public MyQueue() {
stackIn = new Stack();
stackOut = new Stack();
}
public void push(int x) {
stackIn.push(x);
}
public int pop() {
pushToOut();
return stackOut.pop();
}
public int peek() {
pushToOut();
return stackOut.peek();
}
private void pushToOut(){
if(stackOut.empty()){
while(!stackIn.empty()){
stackOut.push(stackIn.pop());
}
}
}
public boolean empty() {
return stackIn.empty() && stackOut.empty();
}
}
2、用队列实现栈
- 思路:
和栈实现队列类似,在出栈、找栈顶元素做改变顺序的处理就行。
不过用队列实现栈 也可以一个容器就行。
因为队列两头都是通的,用length记录队列长度,就可以区分旧元素和新入元素,以此来管理标识轮次(层次遍历迭代法用队列实现时,也有这种做法) - 代码
class MyStack {
ArrayDeque<Integer> mQueue;
int length;
public MyStack() {
mQueue = new ArrayDeque<>();
length = 0;
}
public void push(int x) {
mQueue.add(x);
length++;
}
public int pop() {
for(int i = 0;i<length-1;i++){
mQueue.add(mQueue.poll());
}
length--;
return mQueue.poll();
}
public int top() {
for(int i = 0;i<length-1;i++){
mQueue.add(mQueue.poll());
}
int result = mQueue.peek();
mQueue.add(mQueue.poll());
return result;
}
public boolean empty() {
return mQueue.isEmpty();
}
}
3、前k个高频元素
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
- 思路:
先遍历一遍统计元素和对应出现频次存入map
后面的处理有两种思路:
① 用桶排序 对出现频次进行处理(index为出现频次,value为出现频次为该频次的元素列表);倒序从桶排序结果取 k 个
② 利用优先级队列,将频次和对应元素存入,以频次为比较依据;最后从优先级队列中取出 k 个 - 代码
桶排序写法
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer,Integer> map = new HashMap<>();
for(int n:nums){
map.put(n,map.getOrDefault(n,0)+1);
}
List<Integer>[] frelists = new List[nums.length + 1];
for(int key : map.keySet()){
int i = map.get(key);
if(frelists[i] == null){
frelists[i] = new ArrayList();
}
frelists[i].add(key);
}
List<Integer> res = new ArrayList<>();
for(int i = nums.length; i >= 0 && res.size() < k ;i--){
if(frelists[i]==null)
continue;
res.addAll(frelists[i]);
}
return res.stream().mapToInt(Integer::intValue).toArray();
}
优先级队列写法
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer,Integer> map = new HashMap<>();
int[] result = new int[k];
for(int n:nums){
map.put(n,map.getOrDefault(n,0)+1);
}
PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
public int compare(int[] pair1, int[] pair2) {
return pair2[0] - pair1[0];
}
});
for(int key : map.keySet()){
pq.offer(new int[]{map.get(key),key});
}
while(k-- > 0){
result[k] = pq.poll()[1];
}
return result;
}
4、滑动窗口最大值
- 思路:
优先队列存储滑动窗口最大值,滑动过程将index不符合的值出队,将最大值存入结果集 - 代码:
public int[] maxSlidingWindow(int[] nums, int k) {
int[] result = new int[nums.length - k + 1];
PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
public int compare(int[] pair1, int[] pair2) {
return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1];
}
});
for (int i = 0; i < k; ++i) {
pq.offer(new int[]{nums[i], i});
}
result[0] = pq.peek()[0];
for (int i = k; i < nums.length; i++){
pq.offer(new int[]{nums[i], i});
while(pq.peek()[1] <= i - k){
pq.poll();
}
result[i - k + 1] = pq.peek()[0];
}
return result;
}
总结
- 边界想不清楚就带值进去算
TODO:
各种类型的队列的放入、取出API以及相应特性
LinkedList的add方法和push方法的区别