LeetCode15, somme de trois nombres

Description du titre

Insérez la description de l'image ici

entraine toi

Première approche (échec)

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

Raison: je n'ai pas évité la triple boucle. Parce que je pense que c'est trop compliqué d'utiliser une table de hachage pour éviter le poids.

Référez-vous à la solution officielle

Le problème à prendre en compte lors de l'utilisation de la boucle à trois couches est le problème de la répétition, donc si nous utilisons une table de hachage, c'est très gênant, du moins je pense. Ensuite, nous devons trouver un autre moyen. Un point très important mentionné dans la solution officielle est:将重复的情况一点一点的降低。

  • L'ordre de réduction comme (a, b, c) sera énuméré, mais pas (b, a, c), (c, b, a) et ainsi de suite. -La solution est d'utiliser le tri. On s'assure que les éléments énumérés par le deuxième recyclage ne sont pas inférieurs aux éléments énumérés par le premier recyclage en cours; les éléments énumérés par le troisième recyclage ne sont pas inférieurs aux éléments énumérés par le deuxième recyclage en cours.

Cette méthode résout la situation où tous les nombres sont différents. Mais il y a des situations répétitives telles que: -1, -1, 1, 1, 0; le
tri donne -1, -1, 0, 1, 1. Ensuite, il y a des situations: la première fois trouvée: [-1, - 1,0], la deuxième fois trouvé: [-1,0,1]. En fait, il se répète encore. Comment éviter cette situation? Seulement si l'élément est différent de l'énumération précédente, nous énumérerons.

Pseudo code officiel :

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)


Nous utilisons [-1, -1, -1, -1] pour l'analyse: la première couche boucle sur la première -1, la deuxième couche traverse la seconde -1, la troisième couche traverse la troisième -1, non La somme est satisfaite et égale à 0. Pour revenir au premier niveau d'énumération, car les résultats commençant par -1 ont été énumérés, la prochaine fois que nous énumérons n'est pas -1 et -1 n'est pas autorisé. La même chose est vraie pour la deuxième couche.

tester:

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

Le résultat a expiré: cela
Insérez la description de l'image ici
signifie que la complexité temporelle O (N 3 ) est difficile à passer

La solution officielle ressort: à
cause du a + b que nous avons obtenu des deux premiers cycles, le c qui existe dans le troisième niveau est le seul résultat qui satisfait a + b + c = 0. En même temps, si nous passons au nombre suivant b'of b dans la deuxième itération, nous savons que b '> b, donc le c'qui existe dans la troisième couche est aussi le seul qui satisfait a + b' + c '= 0. Mais parce que b <b ', on peut en déduire c'> c. Et parce que nous
trions , c doit apparaître à gauche de c dans le tableau. En d'autres termes, nous pouvons énumérer b de petit à grand, et en même temps énumérer c de grand à petit, c'est-à-dire que la deuxième boucle et la troisième boucle sont en fait parallèles.

Alors récupérez le pseudo code officiel

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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Cette méthode est ce que nous disons souvent " 双指针(盛最多的水这道题里面也出现了。)". Lorsque nous devons énumérer deux éléments dans un tableau, si nous constatons que lorsque le premier élément augmente, le deuxième élément diminue, alors nous pouvons utiliser des pointeurs doubles Méthode, la complexité temporelle du dénombrement est réduite de O (N 2 ) à O (N). Pourquoi est-ce O (N)? En effet, à chaque étape du processus d'énumération, le "pointeur gauche" se déplacera d'une position vers la droite (c'est-à-dire le b dans le titre) et le "pointeur droit" se déplacera de plusieurs positions vers la gauche, ce qui est lié aux éléments du tableau , Mais nous savons que le nombre de positions qu'il déplacera au total est O (N), qui est uniformément réparti, et il se déplace également d'une position vers la gauche à chaque fois, donc la complexité temporelle est O (N).

Notez qu'il y a la première boucle dans notre pseudocode et que la complexité temporelle est O (N), donc la complexité temporelle totale de l'énumération est O (N 2 ). Puisque la complexité temporelle du tri est O (N \ log N, qui est inférieure à la première au sens asymptotique, la complexité temporelle totale de l'algorithme est O (N 2 ).

Auteur: Lien LeetCode-Solution
: https: //leetcode-cn.com/problems/3sum/solution/san-shu-zhi-he-by-leetcode-solution/
Source: bouton Stay (LeetCode)
copyright réservé par les auteurs. Pour les réimpressions commerciales, veuillez contacter l'auteur pour l'autorisation. Pour les réimpressions non commerciales, veuillez indiquer la source.

tester:

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

Insérez la description de l'image ici
la complexité:
Insérez la description de l'image ici

Je suppose que tu aimes

Origine blog.csdn.net/qq_44861675/article/details/108476396
conseillé
Classement