[LeetCode] -Fila e fila/heap de prioridade

Prefácio

Registre as filas e questões relacionadas à fila prioritária encontradas ao escrever perguntas no LeetCode

fila

225. Use filas para implementar pilhas

Implemente uma pilha usando duas filas. Crie duas filas, fila 1 e fila 2. Quando os dados são inseridos, eles são inseridos em uma das filas. Quando os dados devem ser retirados, os elementos da fila com dados são retirados da fila um por um e inseridos em outra fila. Quando o último elemento da fila com dados é esquerda, é o topo de toda a pilha. Se você quiser retirar um elemento da pilha, apenas retire o último elemento da fila; se quiser obter o elemento do topo da pilha, você deve primeiro usar uma variável inteira para armazenar o valor do elemento e, em seguida, adicione o elemento a outra fila. e, em seguida, retorne esse valor

Portanto, pode-se ver que as duas filas são filas vazias, exceto quando toda a pilha é inicializada e todos os elementos da pilha são removidos. Outras vezes, apenas uma das duas filas não contém elementos. Você deve primeiro julgar ao empurrar, estourar e obter o elemento superior da pilha.

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;
    }
}

Na verdade, uma fila pode implementar uma pilha. Ao obter o elemento superior da pilha, todos os elementos da fila, exceto o último elemento, são retirados da fila e inseridos novamente (ou seja, alterados para o final da fila), de modo que o o último elemento da fila original foi alterado para Basta estar à frente da equipe

239. Fila monotônica máxima de janela deslizante

fila monotônica, ou seja, com base na fila original, estipula-se que os elementos da fila devem ser monotonicamente crescentes ou monotonicamente decrescentes , e só precisam atender a esse requisito, especificamente algumas operações e detalhes dessa fila monotônica, como o desenfileiramento ou enfileiramento de elementos, etc., como implementá-lo depende da situação específica.

Nesta questão, cada vez que a janela se move um bit, a fila monotônica coloca todos os elementos que podem ser o valor máximo na janela deslizante atual. Quando os novos elementos do array trazidos pelo movimento não são processados, fazemos com que a fila diminua monotonicamente , de modo que o elemento principal da fila seja o maior elemento na fila atual e, em seguida, os elementos recém-aparecidos sejam processados ​​e todos os elementos no final da fila que sejam menores que o novo elemento sejam retirados da fila e, em seguida, o novo elemento é adicionado à fila (ou seja, como o novo elemento final), de modo que o novo A fila ainda esteja em ordem decrescente e, como mencionado anteriormente, o que é colocado na fila é o elemento que pode ser o valor máximo no janela deslizante atual (este novo elemento e seus k - 1 elementos anteriores), portanto o valor máximo deve ser o elemento principal da fila. Faça isso sempre que mover a janela e um novo elemento aparecer.

No entanto, para garantir que a fila atual contenha elementos que possam ser o valor máximo da janela atual, você deve primeiro garantir que todos os elementos da fila existam na janela atual, para que a fila no código coloque o subscrito do elemento em a matriz. Ao passar para o elemento com subscrito i, os subscritos de todos os elementos na fila devem ser [i - k + 1,i], portanto, a fila não pode armazenar diretamente os elementos da matriz, mas deve armazenar o índice de subscrito do elemento .

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;
}

fila/heap de prioridade

692. Principais K palavras de alta frequência

Para os k principais, k mais, k maiores e outros problemas semelhantes, filas de prioridade podem ser usadas para resolvê-los.

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. Mediana do fluxo de dados

Usamos dois heaps grandes e pequenos, respectivamente o heap superior grande e o heap superior pequeno, e colocamos os dados no fluxo de dados nesses dois heaps.
Se mantivermos esse relacionamento constante :

Quando o número de elementos no fluxo de dados é um número par, o número de elementos contidos nos dois heaps é igual;
quando o número de elementos no fluxo de dados é um número ímpar, o número de elementos em grande é 1 a mais que isso em pequeno.

Então, quando o número de elementos no fluxo de dados for um número par, a mediana do fluxo de dados será a média dos elementos superiores dos dois heaps; quando o número de elementos no fluxo de dados for um número ímpar, a mediana do fluxo de dados É o elemento superior do grande heap

Então, só precisamos manter essa relação invariante ao adicionarNums, e podemos garantir que quando precisarmos obter a mediana, poderemos obtê-la no tempo O(1).

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();
        }
    }
}

Acho que você gosta

Origin blog.csdn.net/Pacifica_/article/details/126442622
Recomendado
Clasificación