記事のディレクトリ
Leetcode Two Number Sum、Three Number Sum、Four Number Sum Trilogy
1.2つの数値の合計
1.1タイトルの説明
整数配列numsとターゲット値targetが与えられた場合、合計が配列内のターゲット値である2つの整数を見つけて、それらの配列添え字を返します。
各入力は1つの回答にのみ対応すると想定できます。ただし、この配列で同じ要素を再利用することはできません。
例:
与えられたnums = [2、7、11、15]、target = 9
nums [0] + nums [1] = 2 + 7 = 9である
ため、[0、1]を返します。
1.2問題解決のアイデア
非常に簡単です。2つのレベルをトラバースして、合計が目標値に等しい2つの数値を見つけることです。
一方のポインタiを押し続けると、もう一方のポインタjが移動し、1つずつ消えていきます。
1.3Javaコード
class Solution {
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
int[] results = new int[2];
for(int i =0;i<len;i++){
for(int j = i+1;j<len;j++){
if(nums[i]+nums[j] == target){
results[0] = i;
results[1] = j;
return results;
}
}
}
return null;
}
}
2. 三数之和
2.1タイトルの説明
n個の整数を含む配列numsが与えられた場合、a + b + c = 0となるようなnumsに3つの要素a、b、cがあるかどうかを判断しますか?条件を満たすが繰り返されていないすべてのトリプルを見つけます。
注:回答に繰り返しトリプルを含めることはできません。
たとえば、配列nums = [-1、0、1、2、-1、-4]が与えられた場合、
要件を満たすトリプルのセットは次のとおりです。
[
[-1、0、1]、
[-1、-1、2]
]
2.2問題解決のアイデア
紹介するのは少し難しいです。問題は、重複する値の処理です。最も簡単なアイデアは、2つの数値の合計のトラバーサルを継続することですが、3レベルのトラバーサルには十分ではありませんか?しかし...それは本当に良くありません。重複する値を処理するのが面倒であっても、特別な状況(3つの数値が等しい)も考慮され、最後に...タイムアウト!
私は別の方法しか見つけることができません:左右のポインターを中央に移動し、同じものに遭遇した場合、つまり繰り返される要素をスキップする場合は移動を続けるというアイデアを使用してください。
このように動くので、繰り返される要素は互いに隣接している必要があります。繰り返し要素を隣り合わせにする方法は?
ソート!
したがって、最初にソートします。これは、配列の一般的な方法でもあります。並べ替えの利点は、現在の合計のサイズに応じて左右のポインタを移動できることです。
つまり、最初に並べ替えます。値を再度修正し、3つの数値の合計を2つの数値の合計に変換します。つまり、nums [i] + nums [j] + nums [k] = 0はnums [i] + nums [j] = 0-nums [k]に変換されます。
私が移動するとき、繰り返される要素をスキップすることもできます。つまり、コード内です。if(i>0&&nums[i] == nums[i-1]) continue;//略过重复元素
左と右のポインタは、それぞれiの次の要素と最後の要素を指します。
int left = i+1;
int right = len-1;
条件を満たす番号が見つかると、結果セットに追加されます。そして、要素が現在の要素と等しくなくなるまで、左右のポインタを移動します(繰り返される要素は無視します)。
while(left<right&&nums[left]==nums[left+1]){
left++;
}
while(left<right&&nums[right]==nums[right-1]){
right--;
}
left++;
right--;
合計がターゲットよりも大きい場合は、右のポインターが左に移動します。それ以外の場合は、左のポインターが右に移動します。
2.3Javaコード
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
// 先排序
int len = nums.length;
Arrays.sort(nums);
List<List<Integer>> results = new ArrayList<>();
for(int i = 0;i<len;i++){
if(i>0&&nums[i] == nums[i-1]) continue;//略过重复元素
int left = i+1;
int right = len-1;
int newTarget = 0 - nums[i];
while(left<right){
if(nums[left]+nums[right] == newTarget){
List<Integer> temp = new ArrayList<>();
temp.add(nums[i]);
temp.add(nums[left]);
temp.add(nums[right]);
results.add(temp);
while(left<right&&nums[left]==nums[left+1]){
left++;
}
while(left<right&&nums[right]==nums[right-1]){
right--;
}
left++;
right--;
}else if(nums[left]+nums[right] > newTarget){
right--;
}else{
left++;
}
}
}
return results;
}
}
3.4つの数字の合計
3.1タイトルの説明
n個の整数を含む配列numsとターゲット値targetが与えられた場合、a + b + c + dの値がtarget?と等しくなるように、numsに4つの要素a、b、c、およびdがあるかどうかを判断します。条件を満たすが繰り返されない4つのタプルをすべて見つけます。
注意:
回答に4倍の繰り返しを含めることはできません。
例:
配列nums = [1、0、-1、0、-2、2]、およびtarget = 0が与えられます。
要件を満たして四倍のセットがある:
[
[-1、0、0、1]、
[-2、-1、1、2]、
[-2、0、0、2]
]
3.2問題解決のアイデア
3つの数字の合計に似ています。最初に4つの数値の合計を3つの数値の合計に変換し、次に3つの数値の合計を2つの数値の合計に変換します。
これをマスターすると、5つの数字と6つの数字の合計が...恐れることはなくなります。これはすべてルーチンであり、あと数サイクルです。
3.3Javaコード
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> results = new ArrayList<>();
int len = nums.length;
//排序
Arrays.sort(nums);
for(int i = 0;i<len;i++){
if(i>0&&nums[i] == nums[i-1]) continue;
int newTarget1 = target-nums[i];//将四数之和转为三数之和
for(int j = i+1;j<len;j++){
if(j>i+1&&nums[j] == nums[j-1]) continue;
int newTarget2 = newTarget1-nums[j];//将三数之和转为两数之和
int left = j+1;
int right = len-1;
while(left<right){
if(nums[left]+nums[right] == newTarget2){
List<Integer> temp = new ArrayList<>();
temp.add(nums[i]);
temp.add(nums[j]);
temp.add(nums[left]);
temp.add(nums[right]);
results.add(temp);
//跳过重复元素
while(left<right&&nums[left] == nums[left+1]) left++;
while(left<right&&nums[right] == nums[right-1]) right--;
left++;
right--;
}else if(nums[left]+nums[right] > newTarget2){
right--;
}else{
left++;
}
}
}
}
return results;
}
}
PS:「2つの数値の合計」では要素の添え字を返す必要があり、後の2つでは要素の値を返す必要があることに注意してください。これは、最初の質問が単純であるために並べ替えられない理由の1つでもあります。 、必要ありません。並べ替えます。