De la mano contigo escribiendo a mano una cola monótona

Llevarte a mano una cola monótona

I. Resumen

Este artículo lo llevará a comprender a fondo el principio de la cola monotónica y a implementarlo con código. Hay uno para el problema clásico de LeetCode resuelto con colas monótonas: ventana deslizante máxima .

2. Principio

Primero observe el problema que se usa para resolver esta cola monótona: se usa para determinar el valor máximo actual y, por supuesto, también se puede determinar el valor máximo de la ventana deslizante.

Te daré un ejemplo aquí y lo entenderás:

En la actualidad, existe una pandilla de este tipo. La instancia más fuerte puede ser el jefe. Usamos valores numéricos para representar la fuerza. El número máximo de pandilleros es 3. El siguiente es el orden de ingreso a la cuadrilla: 1,3,-1,-3,5,3,6,7, porque solo puede haber un máximo de 3 personas, entonces cuando entre el cuarto, saldrá el que entró primero.

Basado en las reglas anteriores, ahora demostramos el proceso

1. Ven primero1

此时队列中的数据:[1]	//现在1是老大

2. vino por detrás3

此时队列中的数据:[3]	//因为1发现后面来的3比自己还要强,因此肯定是没有可能再当老大了,于是就退出了

3. Entonces entra-1

此时队列中的数据:[3,-1]	// -1进来后发现如果3退休了,自己就有可能当老大,于是留下了

4. Después de eso -3, pensé lo mismo que antes.

此时队列中的数据:[3,-1,-3]	// -3进来后发现如果3退休了,自己就有可能当老大,于是留下了

5. En este momento, llegan 5 y la longitud de la cola es mayor que 3, por lo que el primero sale 3de la cola.

此时队列中的数据:[5]	// 5进来后,其他人就会想,后来的人都这么厉害了,留下来肯定不可能当老大了,于是-1和-3退出了队列

Creo que todos pueden pensar en los próximos pasos. En general, cada vez que llega un nuevo miembro, el miembro cuyo valor es menor saldrá de la cola, ¡porque definitivamente es imposible convertirse en el más grande en el futuro! Después de entender esto, implementemos un código.单调递增队列

3. Implementación del Código

Aquí hay un ejemplo de la pregunta 239 de LeetCode: la ventana deslizante máxima. La cola monotónica en esta pregunta en realidad tiene dos operaciones principales: 1. Verificar si la primera debe salir. ② Determine qué nodos deben salir de la cola. La explicación del código está escrita en los comentarios.

public int[] maxSlidingWindow(int[] nums, int k) {
    
    
		// 特殊情况判断
        if (nums.length == 0) {
    
    
            return new int[]{
    
    };
        }
        if (k == 1) {
    
    
            return nums;
        }
        // 返回的结果
        int[] res = new int[nums.length - k + 1];
        MyQueue queue = new MyQueue(k);
        // 先放k个元素进去
        for (int i = 0; i < k; i++) {
    
    
            queue.put(nums[i], i);
        }
        // 后面的元素一个一个进来
        for (int i = k; i < nums.length; i++) {
    
    
            // 取出当前的最大值
            res[i - k] = queue.getMaxVal();
            // 放入新的元素
            queue.put(nums[i], i);
        }
        res[res.length - 1] = queue.getMaxVal();
        return res;
    }

	/**
	* 自定义的单调递增队列
	*/
    class MyQueue {
    
    
        /**
         * Node节点
         */
        private class Node {
    
    
        	// 数值
            int val;
            // 下标(用于判断是否该出队列)
            int index;
            // 指针
            Node pre, next;

            public Node(int val, int index) {
    
    
                this.val = val;
                this.index = index;
            }
        }

        /**
         * 头指针
         */
        private Node head;

        /**
         * 尾指针
         */
        private Node tail;

        /**
         * Node数量
         */
        private int capacity;

        /**
         * 队列的最大容量 
         *
         * @param capacity
         */
        public MyQueue(int capacity) {
    
    
            this.capacity = capacity;
        }

        public void put(int val, int index) {
    
    
            Node node = new Node(val, index);
            // 检查第一个Node是否该退出了
            checkHeadNode(index);
            // 检查是否右节点要出队
            refreshQueue(val);
            // 添加新节点
            addNodeToLast(node);
        }

        private void checkHeadNode(int maxIndex) {
    
    
            // 有才会检查
            if (head != null) {
    
    
                if (head.index < maxIndex - capacity + 1) {
    
    
                    head = head.next;
                    if (head != null) {
    
    
                        head.pre.next = null;
                        head.pre = null;
                    }
                }
            }
        }

        private void refreshQueue(int newVal) {
    
    
            // 可能节点会退出
            while (tail != null && tail.val < newVal) {
    
    
                tail = tail.pre;
                // tail现在是倒数第二个Node
                if (tail != null) {
    
    
                    tail.next.pre = null;
                    tail.next = null;
                } else {
    
    
                    // 元素删完了
                    head = null;
                }
            }
        }

        private void addNodeToLast(Node node) {
    
    
            // head = tail = null
            if (head == null && tail == null) {
    
    
                // 第一个Node
                head = node;
                tail = node;
            } else {
    
    
                // 拼接在后面
                tail.next = node;
                node.pre = tail;
                tail = node;
            }
        }

		/**
		* 获取当前队列的最大值
		*/
        public int getMaxVal() {
    
    
            if (head != null) {
    
    
                return head.val;
            } else {
    
    
                throw new RuntimeException("队列中没有元素");
            }
        }

		/**
		* 调式使用的方法,打印当前队列
		*/
        private void showQueue() {
    
    
            Node temp = head;
            System.out.println("===========================");
            while (temp != null) {
    
    
                System.out.printf(temp.val + " ");
                temp = temp.next;
            }
            System.out.println("===========================");
        }
    }

Supongo que te gusta

Origin blog.csdn.net/weixin_44829930/article/details/121863668
Recomendado
Clasificación