Cómo eliminar elementos duplicados de una matriz ordenada

Sabemos que para los arreglos, insertar y eliminar elementos al final es más eficiente, y la complejidad del tiempo es O (1), pero si inserta o elimina elementos en el medio o al principio, implicará el movimiento de datos, y la complejidad del tiempo es O (N), la eficiencia es baja.

Entonces, el último artículo  O (1) tiempo para eliminar / encontrar cualquier elemento en la matriz  habló sobre una técnica, intercambiar el elemento a eliminar por el último y luego eliminarlo, puede evitar el movimiento de datos.

PD: He escrito más de 100 artículos originales con cuidado y me he cepillado mano a mano con 200 preguntas de hebilla, todas las cuales se publican en  la hoja de trucos del algoritmo de labuladong , que se actualiza continuamente . Se recomienda recopilar, cepillar las preguntas en el orden de mis artículos , dominar varias rutinas de algoritmos y luego lanzarlas al mar de preguntas.

Desduplicación de matriz ordenada / lista vinculada

Permítanme hablar primero sobre cómo desduplicar una matriz ordenada, primero mire el siguiente tema:

1cbe3f0948d6824aa7dafcd1f1380b7a.jpg

La firma de la función es la siguiente:

int removeDuplicates (int [] nums);

Obviamente, dado que la matriz ha sido ordenada, los elementos duplicados deben estar conectados entre sí. No es difícil encontrarlos, pero si se encuentran todos los elementos duplicados, se eliminarán inmediatamente, es decir, la operación de eliminación se realiza en el medio de la matriz. La complejidad de tiempo total alcanzará O (N ^ 2).

PD: He escrito más de 100 artículos originales con cuidado y me he cepillado mano a mano con 200 preguntas de hebilla, todas las cuales se publican en  la hoja de trucos del algoritmo de labuladong , que se actualiza continuamente . Se recomienda recopilar, cepillar las preguntas en el orden de mis artículos , dominar varias rutinas de algoritmos y luego lanzarlas al mar de preguntas.

Explique brevemente qué es la modificación in situ:

Si no se modifica in situ, podemos directamente int[] crear una nueva  matriz, colocar los elementos después de la deduplicación en esta nueva matriz y luego volver a esta nueva matriz.

Pero la eliminación in situ no nos permite modificar la nueva matriz, solo podemos operar en la matriz original y luego devolver una longitud, de modo que podamos obtener los elementos después de la deduplicación a través de la longitud devuelta y la matriz original.

Este tipo de requisito es muy común en problemas algorítmicos relacionados con arreglos La solución general es  la técnica de puntero rápido y lento en la técnica de puntero doble del artículo anterior  .

Dejamos que el puntero lento  slow vaya detrás, y el puntero rápido  fast camina al frente para explorar el camino, slow y decirle si encontramos un elemento no repetitivo  y dejarnos  slow avanzar. De esta forma, cuando el  fast puntero atraviesa toda la matriz  nums , los nums[0..slow] elementos no se repiten .

int removeDuplicates (int [] nums) { 
    if (nums.length == 0) { 
        return 0; 
    } 
    int lento = 0, rápido = 0; 
    while (rápido <nums.length) { 
        if (nums [rápido]! = nums [lento]) { 
            lento ++; 
            // 维护 nums [0..slow] 无 重复
            nums [lento] = nums [rápido]; 
        } 
        rápido ++; 
    } 
    // 数组 长度 为 索引 + 1 
    devuelve lento + 1; 
}

Mira el proceso de ejecución del algoritmo:

04f34a959ab6f013c90028c8d11241dd.gif

Simplemente expanda, si le da una lista vinculada ordenada, ¿cómo eliminar la duplicación? Esta es la pregunta 83. De hecho, es exactamente lo mismo que la deduplicación de matrices. La única diferencia es que la operación de asignación de matrices se convierte en un puntero de operación:

ListNode deleteDuplicates (ListNode head) { 
    if (head == null) return null; 
    ListNode lento = cabeza, rápido = cabeza; 
    while (rápido! = nulo) { 
        if (rápido.val! = lento.val) { 
            // números [lento] = números [rápido]; 
            lento.siguiente = rápido; 
            // lento ++; 
            lento = lento.siguiente; 
        } 
        // rápido ++ 
        rápido = rápido.siguiente; 
    } 
    // 断开 与 后面 重复 元素 的 连接
    slow.next = null; 
    cabeza de retorno; 
}

3bcd836dd59a37b1fe4dfb97325b5820.gif

8306e7ebbef26302521befe437ec97a2.jpg

La firma de la función es la siguiente:

int removeElement (int [] nums, int val);

El título requiere que   eliminemos nums todos vallos elementos con valores  in situ, y aún necesitamos usar   el puntero de velocidad en la técnica de doble puntero :

Si  fast encuentra un elemento que necesita ser eliminado, omítalo directamente; de ​​lo contrario, dígaselo al  slow puntero y déjelo  slow avanzar un paso.

Esto es exactamente lo mismo que la solución al problema de deduplicación de matrices mencionado anteriormente, por lo que no dibujaré GIF, solo mire el código:

int removeElement (int [] nums, int val) { 
    int rápido = 0, lento = 0; 
    while (rápido <nums.length) { 
        if (nums [rápido]! = val) { 
            nums [lento] = nums [rápido]; 
            lento ++; 
        } 
        rápido ++; 
    } 
    volver lento; 
}

Tenga en cuenta que hay una diferencia importante entre esto y la deduplicación de una matriz ordenada . Aquí nums[slow] asignamos el valor primero  y luego lo damos  slow++, de modo que podamos asegurarnos de  nums[0..slow-1] que no contiene el val elemento de valor  , y la longitud de la matriz de resultado final es  slow.

PD: He escrito más de 100 artículos originales con cuidado y me he cepillado mano a mano con 200 preguntas de hebilla, todas las cuales se publican en  la hoja de trucos del algoritmo de labuladong , que se actualiza continuamente . Se recomienda recopilar, cepillar las preguntas en el orden de mis artículos , dominar varias rutinas de algoritmos y luego lanzarlas al mar de preguntas.

Mover cero

Esta es la pregunta 283 de Leikou. Permítanme describir la siguiente pregunta:

Ingrese una matriz  numspara usted, modifíquela en su lugar , mueva todos los elementos con valor 0 en la matriz al final de la matriz, la firma de la función es la siguiente:

void moveZeroes (int [] nums);

Por ejemplo nums = [0,1,4,0,2], si le da una entrada  , su algoritmo no devuelve un valor, pero  nums modificará la matriz en su lugar  [1,4,2,0,0].

Combinando las preguntas mencionadas anteriormente, ¿ya tienes las respuestas?

El título nos permite mover todos los 0 hasta el final. De hecho, es equivalente a eliminar  nums todos los 0 y luego asignar los siguientes elementos a 0.

Entonces podemos reutilizar la removeElement función de la pregunta anterior  :

void moveZeroes (int [] nums) { 
    // Elimina todo 0 en nums 
    // Devuelve la longitud de la matriz después de eliminar 0 
    int p = removeElement (nums, 0); 
    // Asigna todos los elementos después de p a 0 
    para (; p <nums.length; p ++) { 
        nums [p] = 0; 
    } 
} 

// Vea el código anterior para lograr 
int removeElement (int [] nums, int val);

En este punto, los cuatro problemas del algoritmo de "modificación en el lugar" están terminados. De hecho, el núcleo sigue siendo la técnica del puntero de velocidad. ¿Lo has aprendido?


Supongo que te gusta

Origin blog.51cto.com/15064450/2571028
Recomendado
Clasificación