LeetCode15, suma de tres números

Descripción del Título

Inserte la descripción de la imagen aquí

práctica

Primer acercamiento (falla)

public List<List<Integer>> threeSum(int[] nums) {
    
    

        if(nums==null||nums.length<3){
    
    
            return null;
        }
        List<List<Integer>> lists = new ArrayList<>();
        for(int i=0;i<nums.length-3;i++){
    
    
            for(int j=i+1;j<nums.length-2&&nums[j]>=nums[i];j++){
    
    
                for(int k=j+1;k<=nums.length-1&&nums[k]>=nums[j];k++){
    
    
                    if(nums[i]+nums[j]+nums[k]==0){
    
    

                        ArrayList<Integer> arrayList = new ArrayList<>();
                        arrayList.add(nums[i]);
                        arrayList.add(nums[j]);
                        arrayList.add(nums[k]);
                        lists.add(arrayList);
                    }
                }
            }
        }
        return lists;
    }

Razón: no evité el triple bucle. Porque creo que es demasiado complicado usar una tabla hash para evitar el peso.

Consulte la solución oficial

El problema que debe tenerse en cuenta al usar el bucle de tres capas es el problema de la repetición, por lo que si usamos una tabla hash, es muy problemático, al menos creo. Entonces tenemos que encontrar otra forma. Un punto muy importante mencionado en la solución oficial es:将重复的情况一点一点的降低。

  • Las reducciones como (a, b, c) se enumerarán en este orden, pero no (b, a, c), (c, b, a) y así sucesivamente. -La solución es utilizar la clasificación. Se asegura que los elementos enumerados por el segundo reciclaje no sean menores que los elementos enumerados por el primer reciclaje actual; los elementos enumerados por el tercer reciclaje no sean menores que los elementos enumerados por el segundo reciclaje actual.

Este método resuelve la situación en la que todos los números son diferentes. Pero hay algunas situaciones repetitivas como: -1, -1, 1, 1, 0; la
clasificación da como resultado -1, -1, 0, 1, 1. Luego están las situaciones: la primera vez que se encuentra: [-1, - 1,0], la segunda vez encontrada: [-1,0,1]. De hecho, todavía se repite. ¿Cómo podemos evitar esta situación? Solo si el elemento es diferente de la enumeración anterior, enumeraremos.

Seudocódigo oficial :

nums.sort()
for first = 0 .. n-1
    // 只有和上一次枚举的元素不相同,我们才会进行枚举
    if first == 0 or nums[first] != nums[first-1] then
        for second = first+1 .. n-1
            if second == first+1 or nums[second] != nums[second-1] then
                for third = second+1 .. n-1
                    if third == second+1 or nums[third] != nums[third-1] then
                        // 判断是否有 a+b+c==0
                        check(first, second, third)


Usamos [-1, -1, -1, -1] para el análisis: la primera capa recorre la primera -1, la segunda capa atraviesa la segunda -1, la tercera capa atraviesa la tercera -1, no La suma se satisface y es igual a 0. Volviendo al primer nivel de enumeración, debido a que los resultados que comienzan con -1 han sido enumerados, la próxima vez que enumeramos no es -1, y -1 no está permitido. Lo mismo ocurre con la segunda capa.

prueba:

class Solution {
    
    
    public List<List<Integer>> threeSum(int[] nums) {
    
    
        List<List<Integer>> lists = new ArrayList<>();
        if(nums==null||nums.length<3){
    
    
            return lists;
        }
        Arrays.sort(nums);/*排序*/
        for(int i=0;i<nums.length;i++){
    
    
            if(i==0||nums[i]!=nums[i-1])
            for(int j=i+1;j<nums.length;j++){
    
    
                if(j==i+1||nums[j]!=nums[j-1])
                for(int k=j+1;k<nums.length;k++){
    
    
                    if(k==j+1||nums[k]!=nums[k-1]){
    
    
                        if(nums[i]+nums[j]+nums[k]==0){
    
    
                            ArrayList<Integer> arrayList = new ArrayList<>();
                            arrayList.add(nums[i]);
                            arrayList.add(nums[j]);
                            arrayList.add(nums[k]);
                            lists.add(arrayList);
                        }
                    }
                }
            }
        }
        return lists;
    }
}

El resultado agotó el tiempo de espera:
Inserte la descripción de la imagen aquí
significa que la complejidad de tiempo O (N 3 ) es difícil de superar.

La solución oficial vuelve a salir:
debido al a + b que obtuvimos de los dos primeros ciclos, el c que existe en el tercer nivel es el único resultado que satisface a + b + c = 0. Al mismo tiempo, si pasamos al siguiente número b 'de b en la segunda iteración, sabemos que b'> b, por lo que el c 'que existe en la tercera capa es también el único que satisface a + b' + c '= 0. Pero como b <b ', podemos deducir c'> c. Y como estamos ordenando,
debe aparecer c 'a la izquierda de c en la matriz. En otras palabras, podemos enumerar b de pequeño a grande y al mismo tiempo enumerar c de grande a pequeño, es decir, el segundo ciclo y el tercer ciclo son en realidad paralelos.

Así que obtén el pseudocódigo oficial

nums.sort()
for first = 0 .. n-1
    if first == 0 or nums[first] != nums[first-1] then
        // 第三重循环对应的指针
        third = n-1
        for second = first+1 .. n-1
            if second == first+1 or nums[second] != nums[second-1] then
                // 向左移动指针,直到 a+b+c 不大于 0
                while nums[first]+nums[second]+nums[third] > 0
                    third = third-1
                // 判断是否有 a+b+c==0
                check(first, second, third)

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/3sum/solution/san-shu-zhi-he-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Este método es lo que solemos decir " 双指针(盛最多的水这道题里面也出现了。)". Cuando necesitamos enumerar dos elementos en una matriz, si encontramos que a medida que aumenta el primer elemento, el segundo elemento disminuye, entonces podemos usar punteros dobles Método, la complejidad temporal de la enumeración se reduce de O (N 2 ) a O (N). ¿Por qué es O (N)? Esto se debe a que en cada paso del proceso de enumeración, el "puntero izquierdo" se moverá una posición hacia la derecha (es decir, la b en el título) y el "puntero derecho" se moverá varias posiciones hacia la izquierda, lo que está relacionado con los elementos de la matriz. , Pero sabemos que el número de posiciones que se moverá en total es O (N), que se distribuye uniformemente, y también se mueve una posición a la izquierda cada vez, por lo que la complejidad del tiempo es O (N).

Tenga en cuenta que existe el primer bucle en nuestro pseudocódigo, y la complejidad de tiempo es O (N), por lo que la complejidad de tiempo total de la enumeración es O (N 2 ). Dado que la complejidad temporal de la clasificación es O (N \ log N, que es menor que la primera en un sentido asintótico, la complejidad temporal total del algoritmo es O (N 2 ).

Autor: LeetCode-
Enlace de solución : https: //leetcode-cn.com/problems/3sum/solution/san-shu-zhi-he-by-leetcode-solution/
Fuente: botón de estancia (LeetCode)
copyright reservado por los autores. Para reimpresiones comerciales, comuníquese con el autor para obtener autorización. Para reimpresiones no comerciales, indique la fuente.

prueba:

class Solution {
    
    
   public List<List<Integer>> threeSum(int[] nums) {
    
    
        List<List<Integer>> lists = new ArrayList<>();
        if(nums==null||nums.length<3){
    
    
            return lists;
        }
        Arrays.sort(nums);/*排序*/
        for(int i=0;i<nums.length;i++){
    
    
            if(i==0||nums[i]!=nums[i-1]){
    
    
                int k = nums.length-1;
                int target = -nums[i];
                for(int j=i+1;j<nums.length;j++){
    
    
                    if(j==i+1||nums[j]!=nums[j-1]) {
    
    
                        // 需要保证 b 的指针在 c 的指针的左侧
                        while (j < k && nums[j] + nums[k] > target) {
    
    
                            --k;
                        }
                        // 如果指针重合,随着 b 后续的增加
                        // 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
                        if (j == k) {
    
    
                            break;
                        }
                        if (nums[j] + nums[k] == target) {
    
    
                            List<Integer> list = new ArrayList<>();
                            list.add(nums[i]);
                            list.add(nums[j]);
                            list.add(nums[k]);
                            lists.add(list);
                        }
                    }
                }
            }

        }
        return lists;
    }
}

Inserte la descripción de la imagen aquí
la complejidad:
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_44861675/article/details/108476396
Recomendado
Clasificación