タイトル説明:
配列と数値sを昇順で入力し、それらの合計が正確にsになるように配列内の2つの数値を見つけます。数値の複数のペアの合計がsに等しい場合は、任意のペアを出力します。
例1:
入力:nums = [2,7,11,15]、target = 9
出力:[2,7]または[7,2]
例2:
入力:nums = [10,26,30,31,47,60]、target = 40
出力:[10,30]または[30,10]
限制:
1 <= nums.length <= 10 ^ 5
1 <= nums [i] <= 10 ^ 6
出典:LeetCode(LeetCode)
リンク:https ://leetcode-cn.com/problems/he-wei-sde-liang-ge-shu-zi-lcof
著作権はLeetCodeが所有しています。商用転載の場合は、公認機関にご連絡ください。非商用転載の場合は、出典を明記してください。
問題解決のアイデア:
方法1:二分探索。トピックによって与えられた制限により、トピックを直接暴力的に使用したり、ArrayListを使用したりすることはできません。これは明らかに制限時間を超えます。したがって、既知の番号を持つ別の番号を探す場合、時間コストを削減するためにいくつかの対策を講じる必要があります。与えられた配列は順序付けられているので、二分法は良い方法です。二分法の特定のプロセスは説明されません。
方法2:ダブルポインタ。指定された配列は順序付けられているため、2つのポインターを使用できます。1つのポインターは配列の前端(nums [0])を指し、もう1つのポインターは配列の最後の端(nums [)を指します。 nums.length-1]。
このように、2つのポインタがそれぞれiとjであると仮定すると、配列内に2つの数値が得られます。現在3つの状況があります。
(1)nums [i] + nums [j] == targetの場合、これは次のことを意味します。タイトルに必要な条件の1つが満たされている場合、ループを終了できます。
(2)nums [i] + nums [j]>ターゲットの場合、これはjが指す数が大きすぎることを意味するため、jを1ビット左に移動して比較を続行することをお勧めします。
(3)nums [i] + nums [j] <targetの場合、iが指す数が小さすぎることを示しているため、iを1つ右に移動して、比較を続行することをお勧めします。
配列が順序付けられているため、なぜこれを行うことができますか?iが変更されていない場合、jが指す数とiが指す数の合計がターゲットよりも大きい場合、jの右端の数とnums [ i]大きく追加すると、目標を上回ります。jが変化しない場合、iが指す数とjが指す数の合計がターゲットよりも小さい場合、iの左端の数とnums [j]の加算はターゲットよりも大きくなければなりません。
注:二等分線の時間計算量は、デュアルポインターの時間計算量よりもはるかに高くなります。
二分探索法の時間計算量:O(nlogn)
ダブルポインター法の時間計算量:O(n)
詳細なコード:
public class jianzhi_Offer_57 {
public int[] twoSum(int[] nums, int target) {
int[] ans = new int[2];
int k = 0;
for (int i = 0; i < nums.length; i++){
if(search(nums, i, nums.length-1,target-nums[i]) == true) {
//此处的写法也可和方法二一样
ans[k++] = nums[i];
ans[k++] = target - nums[i];
return ans;
}
}
return ans;
}
//二分查找
public boolean search(int[] nums, int l, int r,int target){
boolean flag = false;
if(l > r)
return flag;
int mid = (l + r) / 2;
if (nums[mid] == target){
flag = true;
}
else if(nums[mid] > target){
flag = search(nums,l,mid - 1,target);
}
else{
flag = search(nums,mid + 1, r,target);
}
return flag;
}
//双指针,一个指针指向数组的前部,一个指针指向数组的后部
//当两个指针所在的数的和比target大时,后指针左移
//当两个指针所在的数的和比target小时,前指针右移
public int[] twoSum1(int[] nums, int target) {
int i = 0, j = nums.length - 1;
while (i < j){
if(nums[i] + nums[j] == target){
int[] ans = new int[]{
nums[i],nums[j]};
return ans;
}
else if((nums[i] + nums[j]) > target){
j--;
}else
{
i++;
}
}
return null;
}
public static void main(String[] args) {
jianzhi_Offer_57 obj = new jianzhi_Offer_57();
int[] nums = new int[]{
15,31,40,43,55,55,56,56,82,98};
int[] ans = obj.twoSum1(nums, 111);
for (int i: ans
) {
System.out.println(i);
}
}
}