誰もが多くのことを知っているが、賢い人はそれを言わない
2 つの数の和の問題については、配列 numsと目標値 targetが与えられるのが一般的ですが、このような問題に対処するには、次の 2 点に注意する必要があります。
-
配列が順序付けされているかどうか。
-
目標値 target が与えられたら、2 つの数値の合計と目標のサイズに従って議論します。
- 目標に等しい
- 目標よりも小さい
- 目標よりも大きい -
戻り値は添字またはスキームの数です
戻り値が添え字である必要がある場合、配列が unordered の場合、ソートとダブルポインターのソリューションでは解決できません。
Leetcodeのトピックと組み合わせて、上記の状況を 1 つずつ説明します。
最初のカテゴリ: 目標に等しい
1. 2 つの数値の合計
整数配列 numsと整数ターゲット値 target が与えられた場合、その合計が配列内のターゲット値 target となる 2 つの整数を見つけて、それらの配列添字を返します。
上記の要約によると、重要なポイントを見つけることができます。
- 順序付けられていない配列。
- 2 つの数値の合計がターゲットに等しくなります。
- 配列の添え字を返します。
したがって、この質問では、並べ替え+ダブル ポインターの解決策は除外されます。ハッシュ テーブルを使用して、時間の複雑さを一定レベルに抑えることをお勧めします。
問題を解決するアイデアは、配列をトラバースし、各要素 num について、対応するターゲット - num があるかどうかを照会することです。
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
if(nums == null || nums.length == 0){
return result;
}
// 注意key为nums[i],value为下标
HashMap<Integer,Integer> hashMap = new HashMap<>();
for(int i = 0;i < nums.length; i++){
if(hashMap.containsKey(target-nums[i])){
result[0] = i;
result[1] = hashMap.get(target-nums[i]);
return result;
}
hashMap.put(nums[i],i);
}
return result;
}
PS: target-nums[i] をハッシュ テーブルに格納することによって実装することもできます。原理は同じです。
1.2 よくある質問
多くの学生は、ここでハッシュテーブルのキーと値が誰であるかについて疑問を持っていますか? 自分を信じてください。この混乱の中にいるのはあなただけではありません。
ここで厳粛に宣言します。
- キー ——— 要素 num[i] または target-nums[i]
- 値 ——— 要素の添え字
多くの混乱は、配列に重複する要素がある場合、キーとして上書きされるという事実によるものです。この質問については、有効な回答が 1 つしかないこと
がタイトルから明らかです。この場合、繰り返し要素があっても、解の集合を見つけて、すぐに戻ります。
問題は、解決策が複数あると仮定した場合、この解決策は有効でしょうか?
答え: はい
例えば:
入力ユース ケースは [1,1,2,5]、ターゲット = 3
2 番目の 1 にトラバースすると、hashMap は前の 1 を上書きしてから実行を続けます。最後に、有効な回答のセット [2,1] が返されます。
紙の上でやっていることはやがて浅はかになり、この問題を実践しなければならないことを私は決して知りません
アルゴリズムの問題を解決するとき、多くの場合、アイデアがないのではなく、実際にそれを認識し始めていません。
167. 2 つの数値の合計 II - ソートされた配列の入力
添え字が 1 から始まる整数の配列番号が与えられます。配列は減少しない順序で配置されています。合計の合計がターゲット番号 target と等しくなるように配列から 2 つの数値を見つけてください。これら 2 つの数値がそれぞれ数値 [index1] と数値 [index2] の場合、1 <= index1 < index2 <= numbers.length です。
これら 2 つの整数のインデックス index1 と index2 を、長さ 2 [index1, index2] の整数の配列として返します。
キーポイント:
- 配列は順序付けられます - 減少しない順序で配置されます。
- 合計がターゲット数 target に等しい 2 つの数を見つけます。
- 添字と index1 < index2 を返します。
- 添字は 1 から始まります。
順序付けられた配列の場合、double pointers、どれが私より優れていますか?
public int[] twoSum(int[] numbers, int target) {
int[] result = new int[2];
if(numbers == null || numbers.length == 0){
return result;
}
int left = 0;
int right = numbers.length - 1;
while(left < right){
int sum = numbers[left]+numbers[right];
if( sum == target){
// 因为下标从1开始,
result[0] = left+1;
result[1] = right+1;
return result;
}
if(sum < target){
left++;
}else{
right--;
}
}
return result;
}
ちなみに、剣はオファー 57 を指しています。合計は s の 2 つの数字です。
2 番目のカテゴリ: 目標未満
1099. K 未満の 2 つの数の最大和
整数配列 nums と整数 k を指定すると、nums[i] + nums[j] = sum および sum < k となるような i < j が存在する最大の合計を返します。この式を満たす i,j が存在しない場合は -1 を返します。
キーポイント:
- 配列順不同
- (合計 = nums[i] + nums[j]) < k;
- 最大のものを返し、可能な限り合計します。
考えないで、ソート+ダブルポインター。
public int twoSumLessThanK(int[] nums, int k) {
if(nums == null || nums.length == 0){
return -1;
}
Arrays.sort(nums);
int left = 0;
int right = nums.length-1;
int result = -1;
while(left < right){
int sum = nums[left] + nums[right];
if(sum >= k){
right--;
}else{
// 求最大和
result = Math.max(result,sum);
left++;
}
}
return result;
}
LCP 28. 調達プログラム
Xiaoli は配列 nums に N 個のパーツの引用を格納します。Xiaoli の予算が目標で、Xiaoli が 2 つのパーツのみを購入し、パーツの購入コストが予算を超えないようにする必要があると仮定すると、Xiaoli の調達計画はいくつありますか?
注: 答えは 1e9 + 7 (1000000007) を法とする必要があります。たとえば、最初の計算結果は 1000000008 です。1 を返します。
要点を要約します。
- 順序付けられていない配列。
- num[i] + num[j] <= ターゲット;
- 条件を満たすスキームの数を見つけます。
この質問はコンテストの質問です.学生の一般的な質問を見てみましょう.
私はそれについて何も言うことはありませんが、Zhang Feiは全員に3回与えました.
この問題を解決するためのコア要素があります:解の数のロック (右境界 - 左境界)です。
public int purchasePlans(int[] nums, int target) {
if(nums == null || nums.length == 0){
return 0;
}
// 排序
Arrays.sort(nums);
int result = 0;
int left = 0;
int right = nums.length - 1;
while(left <= right){
int sum = nums[left] + nums[right];
if(sum > target){
right --;
}else{
// 这里利用[left,right]的元素都符合sum <= target的特性,直接得出方案数为right - left.
result += (right - left);
result %= (1000000007);
left++;
}
}
return result;
}