LeetCode15、3つの数値の合計

タイトル説明

ここに画像の説明を挿入

練習

最初のアプローチ(失敗)

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

理由:トリプルループは避けませんでした。ハッシュテーブルを使用して重みを回避するのはあまりにも難しいと思うので。

公式ソリューションを参照してください

3層ループを使用する際に考慮しなければならない問題は繰り返し問題なので、ハッシュテーブルを使用すると、少なくとも非常に厄介だと思います。次に、別の方法を見つける必要があります。公式ソリューションで言及されている非常に重要なポイントは次のとおりです。将重复的情况一点一点的降低。

  • (a、b、c)のような削減の順序は列挙されますが、(b、a、c)、(c、b、a)などは列挙されません。-解決策は、並べ替えを使用することです。2番目のリサイクルで列挙された要素は、現在の最初のリサイクルで列挙された要素以上であることが保証されます。3番目のリサイクルで列挙された要素は、現在の2番目のリサイクルで列挙された要素以上です。

この方法は、すべての数値が異なる状況を解決します。ただし、-1、-1、1、1、0などの反復的な状況がいくつかあり、
ソートの結果は-1、-1、0、1、1 になります。既存の状況:初めて見つかったとき:[-1、- 1,0]、2回目の検出:[-1,0,1]。実際、それはまだ繰り返されています。どうすればこの状況を回避できますか?要素が前の列挙と異なる場合のみ、列挙します。

公式の疑似コード

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)


分析には[-1、-1、-1、-1]を使用します。最初のレイヤーは最初の-1をループし、2番目のレイヤーは2番目の-1を通過し、3番目のレイヤーは3番目の-1を通過します。合計は満たされ、0に等しくなります。最初のレベルの列挙に戻ると、-1で始まる結果が列挙されているため、次に列挙するときは-1ではなく、-1は許可されません。同じことが第2層にも当てはまります。

テスト:

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

結果がタイムアウトした:
ここに画像の説明を挿入
時間の複雑さO(N 3)を渡すのが難しいことを意味します

公式のソリューションが再び出てきます。
最初の2つのサイクルから取得したa + bのため、3番目のレベルに存在するcは、a + b + c = 0を満たす唯一の結果です。同時に、2回目の反復でbの次の数値b 'にトラバースすると、b'> bとなるため、3番目のレイヤーに存在するc 'も、a + b' + c '= 0を満たす唯一のものです。しかし、b <b 'であるため、c'> cを推定できます。また、並べ替え
を行うため、c は配列のc の左側に表示される必要がありますつまり、bを小さい値から大きい値まで列挙し、同時にcを大きい値から小さい値まで列挙することができます。つまり、2番目のループと3番目のループは実際には並列です。

公式の疑似コードを入手してください

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

このメソッドは、よく " 双指针(盛最多的水这道题里面也出现了。)" と言います。配列内の2つの要素を列挙する必要がある場合、最初の要素が増加すると2番目の要素が減少し、ダブルポインターを使用できることがわかります。方法、列挙の時間の複雑がO(N 2)からO(N)に削減さます。なぜO(N)なのですか?これは、列挙プロセスの各ステップで、「左ポインター」が1つ右(つまり、タイトルのb)に移動し、「右ポインター」が配列の要素に関連する左にいくつかの位置を移動するためです。 、しかし、合計で移動する位置の数はO(N)であり、均等に分散されており、毎回左に1位置移動するため、時間の複雑度はO(N)です。

疑似コードには最初のループがあり、時間の複雑さはO(N)であるため、列挙の合計時間の複雑さはO(N 2であることに注意してくださいソートの時間の複雑さはO(N \ log Nであり、漸近的な意味で前者よりも小さいため、アルゴリズムの合計時間の複雑さはO(N 2)です。

著者:LeetCode-Solution
リンク:https://leetcode-cn.com/problems/3sum/solution/san-shu-zhi-he-by-leetcode-solution/
出典:滞在ボタン(LeetCode)
著作権者が予約。商用転載については、著者に連絡して承認を得てください。非商用転載については、出典を明記してください。

テスト:

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

ここに画像の説明を挿入
複雑さ:
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_44861675/article/details/108476396