三数之和
n個の整数を含む配列numsが与えられた場合、a + b + c = 0となるように、numsに3つの要素a、b、cがあるかどうかを判別します。条件を満たす、繰り返されないすべてのトリプルを見つけてください。
注:回答に繰り返しトリプルを含めることはできません。
例:
配列nums = [-1、0、1、2、-1、-4]が与えられた場合、
要件を満たすトリプルのセットは次のとおりです:
[
[-1、0、1]、
[-1、-1、2]
]
出典:LeetCode
リンク:https ://leetcode-cn.com/problems/3sum
著作権はLeetCodeが所有しています。商用の再版については、公式の承認に連絡してください。非商用の再版については、出典を示してください。
私はこの質問に1日立ち往生し、重いカードに長い時間を費やし、制限時間を超えてさらに半日立ち往生しました。それで、それを記録する必要があると思いました。
このつらい記録を見ると、行の間に2つの単語があります:a〜tui!リトルチキン!!
私の最初のアイデアは、配列を小さいものから大きいものに並べ替え、nums [i]を変更せずに修正し、nums [i +1]をnums [l]、最後の桁nums [nums.length-1]に割り当てることでした。 nums [r]に値を割り当て、nums [i]、nums [l]、nums [r]の3つの数値の合計を計算して、0かどうかを判断し、それが満たされたときに結果セットに追加します。合計<0の場合、l ++; sumsum> 0の場合、r-
当時の私のコードは次のようでした
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
var t=[];
nums.sort((a, b) => a - b);
for(let i=0;i<nums.length;i++){
let l=i+1;
r=nums.length-1;
while(l<r){
if(nums[i]+nums[l]+nums[r]==0){
t.push([nums[i],nums[l],nums[r]]);
l++; r--;
}
else if(nums[i]+nums[l]+nums[r]<0){l++;}
else{r--;}
}
}
return t;
};
次に、重複排除を考慮していなかったことがわかり、出力結果は次のようになりました。
そこで、Setを使用して重複排除を行うことを考えました。現時点では、コードは次のようになっています。
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
var t=[];
nums.sort((a, b) => a - b);
for(let i=0;i<nums.length;i++){
let l=i+1;
r=nums.length-1;
while (nums[i] === nums[++i]) {}
while(l<r){
if(nums[i]+nums[l]+nums[r]==0){
t.push([nums[i],nums[l],nums[r]]);
l++; r--;
}
else if(nums[i]+nums[l]+nums[r]<0){l++;}
else{r--;}
}
}
var newArr = new Set(t);
var arr1 = [...newArr];
return arr1;
};
その後、結果が変わらないことに戸惑い、バイドゥを検索して大物に質問したところ、設定方法はオブジェクトの値ではなく、メモリアドレスを判断することであることがわかりました。まあ、それは本当に私の新人です。
次に、他の人のロジックを参照した後、コードを次のように変更しました。
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
var t=[];
nums.sort((a, b) => a - b);
for(let i=0;i<nums.length;i++){
if (nums[i] > 0) break;
if (i > 0 && nums[i] === nums[i - 1]) continue;//去重
let l=i+1;
r=nums.length-1;
while(l<r){
if(nums[i]+nums[l]+nums[r]==0){
t.push([nums[i],nums[l],nums[r]]);
while (l < r && nums[l] === nums[l + 1]) l++;//去重
while (l < r && nums[r] === nums[r - 1]) r--;//去重
l++; r--;
}
else if(nums[i]+nums[l]+nums[r]<0){l++;}
else{r--;}
}
}
return t;
};
合格しました!さらに、ビッグガイのソリューションが含まれています。今回は、ビッグガイの広告を掲載します(パブリックアカウント:ビッグフロントエンドについて話します。毎週のコンテストのソリューションには強力な控除があり、すべてフロントエンドの人々にとってよりフレンドリーなJavaScriptを使用しています):
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums){
var t=[];
var i=0;
var len=nums.length;
nums.sort((a, b) => a - b);
const record = new Set();
while(i<len)
{
if(nums[i]>0) break;
let l=i+1;
r=len-1;
while(l<r){
var sum=nums[i]+nums[l]+nums[r];
if(sum==0){
const key=[nums[i],nums[l],nums[r]].sort().join(',');
if (!record.has(key)) {
t.push([nums[i],nums[l],nums[r]]);
record.add(key);}
l++; r--;
}
else if(sum<0){l++;}
else{r--;}
i++;
}
}
return t;
};
しかし、これは制限時間を超えています。誰かがこれを最適化する方法があるかどうかはわかりません。指摘してください。