LeetCodeブラッシングノートのDachangシリーズに関与:3つの数字の合計(中)

アルゴリズムを学び、フォースボタンを磨き、ロールに燃料を補給し、大きな工場に入ります!

トピックの説明

トピックへのリンク

n個の整数を含む配列numsが与えられた場合、a + b + c = 0となるようなnumsに3つの要素a、b、cがあるかどうかを判断しますか?合計が0で、繰り返されないすべてのトリプルを見つけてください。

注:回答に重複するトリプルを含めることはできません。

例1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

例2:

输入:nums = []
输出:[]

例3:

输入:nums = [0]
输出:[]

ヒント:

  • 0 <= nums.length <= 3000
  • -105 <= nums [i] <= 105

知識ポイントを含む

これはやや難しい質問ですが、考え方は比較的単純です。最初に頭に浮かぶのはブルートフォースソリューションですが、3つのforループのブルートフォースソリューションがタイムアウトであり、その時間計算量がO(n³)であることは明らかです。しかし、考え方は正しいです。これを最適化して、時間の複雑さを軽減することができます。最初の方法は、ハッシュテーブル方式を使用することです。つまり、最初に並べ替え、次に2つのforループを使用して2つの要素の合計を見つけ、残りの要素にハッシュテーブルを使用して、この値があるかどうかを判断します(注2番目の方法はダブルポインター方式です。つまり、最初に配列がソートされ、次にダブルポインターの移動を使用して、条件を満たす値が検索されます。

上記の分析に基づいて、私たちが知る必要のある知識ポイントは次のとおりです。

  • 配列は、連続したメモリ空間に格納されている同じタイプのデータのコレクションです。
  • 配列の添え字は0から始まります
  • メモリ空間内のアレイのアドレスは連続しています
  • 配列は単純なハッシュテーブルであり、ハッシュテーブルのキーは配列のインデックス添え字です。
  • ハッシュテーブルは、キーに基づいてデータに直接アクセスできます
  • HashSetのcontainsは、ハッシュテーブルにこの値があるかどうかを判断できます

次に、タイトルに従って、キーポイントを抽出できます。

  • 合計が0で、繰り返されないトリプル

質疑応答

Java問題解決策1

思考分析

まず、ハッシュテーブル方式を使用します。つまり、最初に並べ替え、次に2つのforループを使用して2つの要素の合計を見つけ、残りの要素にハッシュテーブルを使用して、この値があるかどうかを判断します(注意してください重複排除)

  • 配列要素を並べ替える
  • 次に、double forループを使用して、重複するタプルを削除します
  • 条件を満たすセットに参加する
class Solution {
    
    
    public List<List<Integer>> threeSum(int[] nums) {
    
    

       //处理特殊情况
      if(nums.length<3) 
        return new ArrayList<List<Integer>>();//实例化只需要最外层指定具体实现集合类

      List<List<Integer>> res = new ArrayList<List<Integer>>();//初始化结果集合

      Arrays.sort(nums); //排序
       for(int i=0;i<nums.length;i++){
    
    
            if(i>0 && nums[i]==nums[i-1])
                continue; //去掉重复元组
            int target = -nums[i];
            HashSet<Integer> set = new HashSet<Integer>(); //集合来判断是否满足条件
            for(int j=i+1;j<nums.length;) {
    
    
                //如果存在元素满足条件,执行以下逻辑
                if(set.contains(target-nums[j])){
    
    
                    ArrayList<Integer> tmp = new ArrayList<Integer>();
                    tmp.add(nums[i]);
                    tmp.add(nums[j]);
                    tmp.add(target-nums[j]);
                    res.add(tmp);
                    //如果寻找到解,那么不需要将nums[j]加入set,因为此时已经将nums[j]作为答案赋值给res了,nums[j]已经不可能和其他元素搭配组成答案了。
                    //寻找到一个解,如果下一个元素值和当前值一样,那么会出现一个重复的答案,所以直接跳过,直到出现不一样的元素
                    j++;
                    while(j<nums.length&&nums[j]==nums[j-1]){
    
    
                        j++;
                    }
                }else{
    
    
                    //如果当前元素不存在,同时也不满足解条件,那么将当前元素加入set
                    set.add(nums[j++]);
                }
            }
        }
            return res;

    }
}

ここに画像の説明を挿入

Java問題ソリューション2

思考分析

2番目の方法は、ダブルポインター方式です。つまり、最初に配列がソートされ、次にダブルポインターの移動を使用して、条件を満たす値が検索されます。具体的なアイデアは次のとおりです。

  • 重複排除を簡単にするために最初に並べ替える
  • 次に、トラバーサルを実装するための最初の固定ポインターkを定義します
  • 次に、ダブルポインタの左と右のポインタiとjがあり、左のポインタiはkの後ろにあり、右のポインタjは配列の右端にあります。
  • 左右のポインタが交差しない場合は、左のポインタが右に移動し、右のポインタが左に移動します。
  • 条件が満たされている場合はリストコレクションに追加します。満たされていない場合は、固定ポインターを移動した後、上記の手順を繰り返します。

コード

class Solution {
    
    
    public List<List<Integer>> threeSum(int[] nums) {
    
    
   
       Arrays.sort(nums); //数组排序,方便去重
        List<List<Integer>> res = new ArrayList<>(); //结果集合

        for(int k = 0; k < nums.length - 2; k++){
    
     //k是第一个固定的指针
            if(nums[k] > 0)  //k位置的都大于0了,后面的肯定都大于0了
                break;
            if(k > 0 && nums[k] == nums[k - 1])  //去重
                continue;
            int i = k + 1; //双指针的左边的指针
            int j = nums.length - 1;  //双指针的右边的指针
            while(i < j){
    
     //满足左边指针在左边,右边指针在右边(不交叉)
                int sum = nums[k] + nums[i] + nums[j]; //求和
                if(sum < 0){
    
     //和小于0,左边指针向右移动
                    while(i < j && nums[i] == nums[++i]);
                } else if (sum > 0) {
    
    //和大于00,右边指针向左移动
                    while(i < j && nums[j] == nums[--j]);
                } else {
    
     //和等于0,满足条件,元素放入结果集合
                    res.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j])));
                    //想要找下一个0的话,必须左指针元素值增加,右指针元素值减小
                    while(i < j && nums[i] == nums[++i]);//左指针继续右移(在0的基础上增加)
                    while(i < j && nums[j] == nums[--j]); //右指针继续左移(在0的基础上减少)
                }
            }
        }
        return res; //返回结果集合
    }
}

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/weixin_44480968/article/details/124027493