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:
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:
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; }
La firma de la función es la siguiente:
int removeElement (int [] nums, int val);
El título requiere que eliminemos nums
todos val
los 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 nums
para 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?