[アルゴリズム - ダブルポインタ] LeetCode 15 3 つの数値の合計

トピックの説明:

問題解決のアイデア: ダブルポインタ

        まず、配列を昇順に並べ替えます。次に、次の手順を使用して問題を解決できます。

        空の結果セット result を初期化して、合計が 0 である見つかったトリプルを格納します。

        最後から 3 番目の要素まで配列全体をスキャンします (必要なのはトリプルであるため)。各要素について、2 つのポインター (左ポインター L と右ポインター R) を使用して、合計が 0 であるすべてのトリプルを検索します。

  1. 左ポインタ L を初期化して現在の要素の次の要素に設定し、右ポインタ R を初期化して配列の最後の要素に設定します。
  2. 現在の要素が前の要素と同じである場合 (存在する場合)、重複したソリューションを避ける必要があるため、単純に現在の要素をスキップし、次の要素に進みます。
  3. 現在の要素 nums[i] について、nums[i] + nums[L] + nums[R] の合計を確認します。
    1. 合計が 0 未満の場合は、左ポインタ L をインクリメントします。
    2. 合計が 0 より大きい場合は、右ポインタ R を減らします。
    3. 合計が 0 に等しい場合は、このトリプレット [nums[i], nums[L], nums[R]] を結果セットの結果に追加し、合計が 0 になるまで左ポインタ L と右ポインタ R を同時に移動します。現在の要素と同じ要素が見つかりました 等しくない要素 (ソリューションの重複を避けるため)。
    4. 最後に、結果セットの結果が返されます。

        配列全体を走査する必要があり、各要素を 1 回走査する必要がある場合があるため、このメソッドの時間計算量は O(n^2) です。

        実装を作成するときは、解決策の重複を避けるために、左右のポインターを処理するときに必ず等しくない要素に移動してください。

コード:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) 
    {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        for(int i = 0; i < nums.size() - 1; i++)
        {  
            if(nums[i] > 0)
                return result;    //数组递增
            if(i > 0 && nums[i] == nums[i - 1])
            {
                continue;    //对a去重,如果i=1与i=0对应的元素相同,那么跳过下面的所有操作,left,right不需要考虑了。
            }
            //a满足去重,再来确定left,right以及去除问题。
            int left = i + 1;
            int right = nums.size() - 1;
            while(left < right)
            {
                //当left==right时,b,c为同一个数,不符合要求。
                if(nums[i] + nums[left] + nums[right] < 0) 
                    left++;
                else if(nums[i] + nums[left] + nums[right] > 0) 
                    right--;
                else
                {
                    vector<int> v = {nums[i], nums[left], nums[right]};
                    result.push_back(v);
                    //下面考虑left,right的移动情况。
                    while (right > left && nums[right] == nums[right - 1])
                        right--;
                    //再次加上right>left的原因是:进入上面的循环时是复合right>left的,但是
                    //可能在循环中left与right发生改变。
                    while (right > left && nums[left] == nums[left + 1]) 
                        left++;
                    /*
                    为什么是while?举个例子
                    [0 -1 -1 -1 -1 -1 1 1 1 1 1 1 ]
                    因为当i= 0时,left与right就已经收集到了正确的结果
                    此时应该持续地移动left 与 right,一次是不够。
                    */
                   
                    left++;
                    right--;

                    //是为了在找到一个有效的三元组后,将left和right分别向前和向后移动一位,以便在后续的循环中继续寻找其他可能的三元组。这样可以确保所有的有效三元组都被找到。
                }
            }
        }           
    return result;   
    }
};

結果:

おすすめ

転載: blog.csdn.net/weixin_44906102/article/details/133418632
おすすめ