一年近くアルゴリズムの本をかじり続けているのですが、口で考えてもカスしか残らないはずですが、頭の中で何を考えていますか?? ?
- いつか「もう食べ終わった、もういらない、別の本に変えたい」と思ってほしいと心から願っています。? 罪罪!!!
- ははは
記事ディレクトリ
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 思考分析
-
target-nums[i]
最初の数値 nums[i] を決定した後、残りの 2 つの数値は2 つの数値の合計になります。- 3 つの数値の合計 ------" 2 つの数値の合計
2-1-3 重複排除ロジックを考える
重複排除といえば、実際、主に考慮すべきは 3 つの番号の重複排除です。a、b、c、nums[i]、nums[left]、nums[right] に対応
2-1-3-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 つの繰り返し次元があります。次に、次のように書く必要があります。
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の重複排除
- 多くの学生がこの質問を書いたとき、重複排除のロジックに右と左の重複排除が追加されました: (コードのコメント部分)
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 {
}
}
-
この種の重複排除は、実際にはプログラムの効率を向上させるのには役立ちません。
- 右の重複排除を例に挙げます。この重複排除ロジックが追加されていなくても、
while (right > left) 和 if (nums[i] + nums[left] + nums[right] > 0)
right-- の操作は に従って完了します。 - while (left < right && nums[right] == nums[right + 1]) right–; を追加 このコード行は事前に実行する必要があるロジックを実際に実行しますが、判定ロジックを削減するものではありません。
- 右の重複排除を例に挙げます。この重複排除ロジックが追加されていなくても、
-
-
最も単純な思考プロセスは、権利が 1 つずつ減算されるため、減算はどこでも同じであるということです。
-
したがって、この種の重複排除は省略できます。それは重複排除のロジックを前進させるだけです。
-