[LeetCode]-Queue & Priority Queue/Heap

Preface

Record the queues and priority queue-related questions encountered when writing questions on LeetCode

queue

225. Implement a stack with a queue

Implement a stack using two queues. Create two queues, queue 1 and queue 2. When data is input, it is input into one of the queues. When data is to be taken out, the elements of the queue with data are dequeued one by one and entered into another queue. When the last element of the queue with data is left, it is the top of the entire stack. If you want to pop an element from the stack, just dequeue the last element; if you want to get the top element of the stack, you must first use an Integer variable to store the value of the element, and then add the element to another queue. , and then return this value

So it can be seen that the two queues are empty queues except when the entire stack is initialized and all elements in the stack are popped. At other times, only one of the two queues does not contain elements. You must first judge when pushing, popping, and getting the top element of the stack.

class MyStack {
    
    
    private LinkedList<Integer> queue1;
    private LinkedList<Integer> queue2;
    public MyStack() {
    
    
        queue1 = new LinkedList<>();
        queue2 = new LinkedList<>();
    }
	//入栈
    public void push(int x) {
    
    
        if(queue1.peek() == null){
    
    
            queue2.offer(x);
        }else {
    
    
            queue1.offer(x);
        }
    }
	//出栈
    public int pop() {
    
    
        if(queue1.peek() == null){
    
    
            if(queue2.peek() == null){
    
    
                return -1;
            }else {
    
    
                while (queue2.size() > 1){
    
    
                    queue1.offer(queue2.poll());
                }
                return queue2.poll();
            }
        }else {
    
    
            while (queue1.size() > 1){
    
    
                queue2.offer(queue1.poll());
            }
            return queue1.poll();
        }
    }
	//获取栈顶元素
    public int top() {
    
    
        if(queue1.peek() == null){
    
    
            if(queue2.peek() == null){
    
    
                return -1;
            }else {
    
    
                while (queue2.size() > 1){
    
    
                    queue1.offer(queue2.poll());
                }
                Integer value = queue2.peek();
                queue1.offer(queue2.poll());
                return  value;
            }
        }else {
    
    
            while (queue1.size() > 1){
    
    
                queue2.offer(queue1.poll());
            }
            Integer value = queue1.peek();
            queue2.offer(queue1.poll());
            return value;
        }
    }
	//判断栈中是否为空
    public boolean empty() {
    
    
        return queue1.size() == 0 && queue2.size() == 0;
    }
}

In fact, a queue can implement a stack. When obtaining the top element of the stack, all elements in the queue except the last element are dequeued and re-entered (that is, changed to the end of the queue), so that the last element in the original queue is changed to The head of the team is fine.

239. Sliding window maximum-monotonic queue

monotonic queue, that is, based on the original queue, it is stipulated that the elements in the queue must be monotonically increasing or monotonically decreasing , and only need to meet this requirement, specifically some operations and details of this monotonic queue, such as the dequeuing or enqueuing of elements, etc. , how to implement it depends on the specific situation.

In this question, each time the window moves one bit, the monotonic queue puts all the elements that may be the maximum value in the current sliding window. When the new array elements brought by the movement are not processed, we make the queue monotonically decrease, so that the queue The head element is the largest element in the current queue, and then the newly appearing elements are processed, and all elements at the end of the queue that are smaller than the new element are dequeued, and then the new element is added to the queue (that is, as the new tail element), so that the new The queue is still in descending order, and as mentioned earlier, what is placed in the queue is the element that may be the maximum value in the current sliding window (this new element and its previous k - 1 elements), so the maximum value must be the head element of the queue. up. Just do this every time you move the window and a new element appears.

However, to ensure that the current queue contains elements that may be the maximum value of the current window, you must first ensure that all elements in the queue exist in the current window, so the queue in the code places the subscript of the element in the array. When traversing to the element with subscript i, the subscripts of all elements in the queue must be [i - k + 1,i], so the queue cannot directly store array elements, but must store the subscript index of the element.

public int[] maxSlidingWindow(int[] nums, int k) {
    
    
    LinkedList<Integer> monotonousQueue = new LinkedList<>();
    //先对前k个元素进行处理,初始化单调队列
    for (int i = 0; i < k; i++) {
    
    
        while (!monotonousQueue.isEmpty() && nums[monotonousQueue.peekLast()] < nums[i]){
    
    
            monotonousQueue.removeLast();
        }
        monotonousQueue.offer(i);
    }
    int[] res = new int[1 + nums.length - k];
    int index = -1;
    for(int i = k;i < nums.length;i++){
    
    
        res[++index] = nums[monotonousQueue.peek()];
        //排除掉不可能存在当前窗口的元素
        while (!monotonousQueue.isEmpty() && monotonousQueue.peek() < i - k + 1){
    
    
            monotonousQueue.poll();
        }
        while (!monotonousQueue.isEmpty() && nums[monotonousQueue.peekLast()] < nums[i]){
    
    
            monotonousQueue.removeLast();
        }
        monotonousQueue.offer(i);
    }
    //循环中最后一个元素处理完后,它的窗口的最大值没有被放入结果数组
    res[++index] = nums[monotonousQueue.peek()];
    return res;
}

priority queue/heap

692. Top K High Frequency Words

For the top k, k most, k largest and other similar problems, you can use priority queues to solve them.

public List<String> topKFrequent(String[] words, int k) {
    
    
//先构建一个字符串与其出现次数的map
    Map<String, Integer> map = new HashMap<String, Integer>();
    for (String word : words) {
    
    
        map.put(word, map.getOrDefault(word, 0) + 1);
    }
    //将每个键值对添加到优先队列中
    PriorityQueue<Map.Entry<String, Integer>> pq = new PriorityQueue<>((entry1,entry2) -> {
    
    
        //使用lambda表达式创建一个函数式接口comparator的对象
        //如果出现了相同次数,就按字典序升序;否则按出现次数的降序
        return entry1.getValue().equals(entry2.getValue()) ? entry1.getKey().compareTo(entry2.getKey()) : entry2.getValue() - entry1.getValue();
    });
    pq.addAll(map.entrySet()); //map.enttrySet().forEach(pq::add);
    List<String> res = new ArrayList<String>();
    //取前k个
    for(int i = 0;i < k;i++){
    
    
        res.add(pq.poll().getKey());
    }
    return res;
}

295. Median of data stream

We use two heaps big and small, respectively the big top heap and the small top heap, and put the data in the data stream into these two heaps.
If we maintain this constant relationship :

When the number of elements in the data stream is an even number, the number of elements contained in the two heaps is equal;
when the number of elements in the data stream is an odd number, the number of elements in big is 1 more than that in small.

Then, when the number of elements in the data stream is an even number, the median of the data stream is the average of the top elements of the two heaps; when the number of elements in the data stream is an odd number, the median of the data stream It is the top element of the big heap

Then, we only need to maintain this invariant relationship when addingNums, and we can ensure that when we need to obtain the median, we can obtain it in O(1) time.

class MedianFinder {
    
    
    PriorityQueue<Integer> big = new PriorityQueue<>((a,b) -> b - a);
    PriorityQueue<Integer> small = new PriorityQueue<>((a,b) -> a - b);
    public void addNum(int num) {
    
    
        int bigSize = big.size();
        int smallSize = small.size();
        if(bigSize == smallSize){
    
     //1. 两个堆大小相等,此时我们要让big中比small多一个元素
            //1.1 如果有一个堆为空,说明两个都为空,此时要加入第一个元素,直接加到big中即可;
            //    如果两个堆不为空,那么如果num小于等于big的堆顶元素,就加到big中即可
            if(bigSize == 0 || num <= big.peek()){
    
     
                big.add(num);
            }else{
    
     //1.2 如果num大于big堆顶元素,说明num应该加到small中,那么为了让big中比small多一个元素,就要取出small的堆顶元素到big中
                small.add(num);
                big.add(small.poll());
            }
        }else{
    
     //2. 两个堆大小不相等,说明此时big中比small中多一个元素,我们要让big跟small中元素数量相等
            //2.1 如果num大于big堆顶元素,就加到small中即可
            if(num > big.peek()){
    
    
                small.add(num);
            }else{
    
    
                //2.2 如果num小于等于big堆顶元素,就应该把num加到big中,然后把big的堆顶元素加到small中从而两个堆数量相等
                big.add(num);
                small.add(big.poll());
            } 
        }
    }
    public double findMedian() {
    
    
        int bigSize = big.size();
        int smallSize = small.size();
        if(bigSize == smallSize){
    
    
            if(bigSize == 0){
    
    
                return 0;
            }else{
    
    
                return (big.peek() + small.peek()) / 2.0; //注意,平均值要取小数
            }
        }else{
    
    
            return big.peek();
        }
    }
}

Guess you like

Origin blog.csdn.net/Pacifica_/article/details/126442622