リコウ: 2 つの数値の合計と n つの数値の合計に対する (マップ) および (ソート + ダブル ポインター) の解 [3 回のブラシを経て、HashMap 合計の重複排除問題がようやく理解されました]

一年近くアルゴリズムの本をかじり続けているのですが、口で考えてもカスしか残らないはずですが、頭の中で何を考えていますか?? ?

  • いつか「もう食べ終わった、もういらない、別の本に変えたい」と思ってほしいと心から願っています。? 罪罪!
  • ははは

1. 2 つの数値の合計

1-1

  • 2 つの数値の合計 [配列の添え字を返す] は、HashMap を使用して非常に簡単に解くことができ、非常に簡単です。
  • 並べ替え + ダブル ポインターにより、n 個の数値の合計 [配列要素を返す] への道が開かれます。
    • ソート後、配列の添字に対応する要素が変更されます。

1-1-1ソート+ダブルポインタ【復帰!配列要素です!配列の添字ではありません]

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    
    
    // 当需要返回结果数组时
    // 排序+双指针
    nums.sort((a,b) => {
    
    return a-b;})
    let left = 0,right = nums.length-1;
    
    const res = [];

    // 左右指针
   while(left < right) {
    
    
       let leftValue = nums[left],rightValue = nums[right];
       let sum = leftValue + rightValue
       
       if(sum < target){
    
    
           while(left < right && nums[left] == leftValue) left++;  
       } 
       else if(sum > target) {
    
    
           while (left < right && nums[right] == rightValue)  right--;
       }
       else {
    
    
           res.push(nums[left],nums[right])
           while(left < right && nums[left] == leftValue ) left++;
           while(left < right && nums[right] == rightValue ) right--;
       }
   }

   return res;
};

1-1-2 HashMap の2 つの数値の合計

  • hashMap を使用して、走査された要素と対応するインデックスを保存します。
  • 要素が走査されるたびに、hashMap 内の要件を満たすターゲット番号があるかどうかを確認します。
  • すべてがワンパスで完了します(時間の余裕)
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    
    
   const map = new Map();
   for(let i in nums) {
    
    
    
    if(map.get(target - nums[i])) {
    
    
        return [i,map.get(target - nums[i])]
    }
    map.set(nums[i],i)
   } 
};

2. 3 つの数値の合計 [配列要素を返す]

2-1 3 つの数字の合計

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

2-1-1ソート+ダブルポインタ

ここに画像の説明を挿入

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    
    
    return threeSumTarget(nums, 0)
};
const threeSumTarget = (nums, target) => {
    
    
    nums.sort((a,b)=>a-b)
    // const res = new Set();
    const res= [];
    for(let i = 0; i<nums.length; i++) {
    
    
        let temp = towSumTarget(nums, i+1, target - nums[i])
        if(temp.length) {
    
    
            for(let item of temp) {
    
    
                item.push(nums[i])
                res.push(item);
            }
        }
        // 跳过第一个数字重复的情况,否则会出现重复结果
        while(i < nums.length-1 && nums[i]==nums[i+1]) i++;
    }
    return res;
}
var towSumTarget = function(nums, start, target) {
    
    

    // 当需要返回结果数组时
    // 排序+双指针
    nums.sort((a,b) => {
    
    return a-b;})
    let left = start,right = nums.length-1;
    
    const res = [];

    // 左右指针
   while(left < right) {
    
    
       let leftValue = nums[left];
       let rightValue = nums[right];
       if(nums[left] + nums[right] < target) left++;
       else if(nums[left] + nums[right] > target) right--;
       else {
    
    
           res.push([nums[left],nums[right]])
           while(left < right && nums[left] == leftValue ) left++;
           while(left < right && nums[right] == rightValue ) right--;
       }
   }

   return res;
};




2-1-2 思考分析

  1. target-nums[i]最初の数値 nums[i] を決定した後、残りの 2 つの数値は2 つの数値の合計になります。

    • 3 つの数値の合計 ------" 2 つの数値の合計
  2. 画像の説明を追加してください

2-1-3 重複排除ロジックを考える

重複排除といえば、実際、主に考慮すべきは 3 つの番号の重複排除です。a、b、c、nums[i]、nums[left]、nums[right] に対応

2-1-3-1 重複排除

  1. 分析する

    • a が繰り返された場合はどうなるでしょうか。a は nums で走査される要素であるため、直接スキップする必要があります。

      • ただし、ここで nums[i] が nums[i + 1] と同じかどうかを判断するか、nums[i] が nums[i-1] と同じかどうかを判断するかという問題があります。

      • それらはすべて、前のものと後のものを比較するかどうかに関係なく、nums[i] と比較されます。

        if (nums[i] == nums[i + 1]) {
                  
                   // 去重操作
            continue;
        }
        
    • 次に、トリプレット内の繰り返し要素のケースを直接渡します。たとえば、 {-1, -1 ,2} このデータセットは、最初の -1 まで移動すると、次のデータも -1 であると判断され、このデータセットが渡されます。

      • 私たちがしなければならないことは、トリプルを繰り返すことはできませんが、トリプル内の要素は繰り返すことができるということです。
  2. したがって、ここには 2 つの繰り返し次元があります。次に、次のように書く必要があります。

if (i > 0 && nums[i] == nums[i - 1]) {
    
    
    continue;
}
  • この方法を書くには、現在 nums[i] を使用しています。最初の -1 に到達するときに、データのセット {-1, -1 ,2} を見て、前の要素が同じ要素であるかどうかを判断します。前のもの -1 がない場合は、{-1, -1 ,2} も結果セットに含めることができます。

2-1-3-2 bとcの重複排除

  1. 多くの学生がこの質問を書いたとき、重複排除のロジックに右と左の重複排除が追加されました: (コードのコメント部分)
while (right > left) {
    
    
    if (nums[i] + nums[left] + nums[right] > 0) {
    
    
        right--;
        // 去重 right
        while (left < right && nums[right] == nums[right + 1]) right--;
    } else if (nums[i] + nums[left] + nums[right] < 0) {
    
    
        left++;
        // 去重 left
        while (left < right && nums[left] == nums[left - 1]) left++;
    } else {
    
    
    }
}
  1. この種の重複排除は、実際にはプログラムの効率を向上させるのには役立ちません。

    • 右の重複排除を例に挙げます。この重複排除ロジックが追加されていなくても、while (right > left) 和 if (nums[i] + nums[left] + nums[right] > 0)right-- の操作は に従って完了します。
    • while (left < right && nums[right] == nums[right + 1]) right–; を追加 このコード行は事前に実行する必要があるロジックを実際に実行しますが、判定ロジックを削減するものではありません。
    • 最も単純な思考プロセスは、権利が 1 つずつ減算されるため、減算はどこでも同じであるということです。

    • したがって、この種の重複排除は省略できます。それは重複排除のロジックを前進させるだけです。

おすすめ

転載: blog.csdn.net/hannah2233/article/details/128536805
おすすめ