日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

LeetCode 167. 两数之和 II - 输入有序数组 思考分析

發(fā)布時間:2023/12/1 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LeetCode 167. 两数之和 II - 输入有序数组 思考分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

  • 1、暴力,超時
  • 2、雙指針+滑動窗口+條件限制 AC
  • 3、觀看題解(吸取他人經(jīng)驗(yàn))
    • 1、二分查找
    • 2、雙指針
    • 3、雙指針+二分查找

給定一個已按照升序排列 的有序數(shù)組,找到兩個數(shù)使得它們相加之和等于目標(biāo)數(shù)。

函數(shù)應(yīng)該返回這兩個下標(biāo)值 index1 和 index2,其中 index1 必須小于 index2。

說明:

返回的下標(biāo)值(index1 和 index2)不是從零開始的。
你可以假設(shè)每個輸入只對應(yīng)唯一的答案,而且你不可以重復(fù)使用相同的元素。
示例:

輸入: numbers = [2, 7, 11, 15], target = 9
輸出: [1,2]
解釋: 2 與 7 之和等于目標(biāo)數(shù) 9 。因此 index1 = 1, index2 = 2 。

1、暴力,超時

class Solution { public:vector<int> twoSum(vector<int>& numbers, int target) {int n = numbers.size();int flag=0;vector<int> res;for(int i=0;i<n;i++){flag=0;for(int j=i+1;j<n;j++){if(numbers[i]+numbers[j]==target){res.emplace_back(i+1);res.emplace_back(j+1);flag=1;break;}}if(flag==1) break;}return res;} };

2、雙指針+滑動窗口+條件限制 AC

在做題提交的過程中發(fā)現(xiàn)了幾處不容易想到的地方:
1、numbers中的元素是遞增的,但是這個遞增不是numbers[i]<numbers[i],而是numbers[i]<=numbers[i+1]
2、numbers中的元素有正有負(fù),可能連續(xù)好幾個都是0
3、一開始我想:首先找到小于等于target的元素個數(shù),這樣的話兩個值只需要在這些元素中找就可以了,但是事實(shí)并非如此。
例如:target=0,numbers[]= {-3,3,.....},如果用numbers[i]<=target,顯然只能到第一個元素,所以我又添加了一個限制條件:
(i>=1 && numbers[i-1]+numbers[i]==0)(因?yàn)橛^察的是兩個元素相加的結(jié)果,所以這樣肯定是對的)
所以根據(jù)思考之后的修改為:

for(int i=0;i<n;i++) {if(numbers[i]<=target || numbers[i]==0 ||(i>=1 && numbers[i-1]+numbers[i]==0)){num_smaller_than_target++;}else{break;} }

之后只需要在0~num_smaller_than_target-1的范圍內(nèi)尋找兩個數(shù)就可以了!
然后使用雙指針,一開始L指向0,R指向num_smaller_than_target-1,并且保證L<R來循環(huán)
在循環(huán)過程中,時時注意sum = numbers[L]+numbers[R],
1、如果sum==target,說明我們已經(jīng)找到值了,直接退出
2、如果sum<target,說明左值一定過小(右邊界由于是從大到小縮減的,此時不做改變,因?yàn)橐膊淮_定右邊界是大是小)
3、如果sum>target,說明右值一定過大,選擇減少右值(由于左邊界是從小到大的,此時不做改變,因?yàn)橐膊淮_定左邊界是大是小)

class Solution { public:vector<int> twoSum(vector<int>& numbers, int target) {int n = numbers.size();int flag=0;vector<int> res;int num_smaller_than_target=0;//首先找到小于等于target的元素個數(shù)for(int i=0;i<n;i++){if(numbers[i]<=target || numbers[i]==0 ||(i>=1 && numbers[i-1]+numbers[i]==0)){num_smaller_than_target++;}else{break;} }int L=0;int R=num_smaller_than_target-1;//兩個指針從兩邊往中間縮while(L<R){int sum = numbers[L]+numbers[R];if(sum==target){res.emplace_back(L+1);res.emplace_back(R+1);break;}//當(dāng)和小于目標(biāo),說明,左值肯定過小else if(sum<target){L++;}//當(dāng)和大于目標(biāo),說明,右值肯定過大else {R--;}}return res;} };


因?yàn)橛幸?#xff1a;

所以我們來驗(yàn)證一下重復(fù)結(jié)果是否輸出一致:

顯然正確。

3、觀看題解(吸取他人經(jīng)驗(yàn))

1、二分查找

在數(shù)組中找到兩個數(shù),使得它們的和等于目標(biāo)值,可以首先固定第一個數(shù),然后尋找第二個數(shù),第二個數(shù)等于目標(biāo)值減去第一個數(shù)的差。利用數(shù)組的有序性質(zhì),可以通過二分查找的方法尋找第二個數(shù)。為了避免重復(fù)尋找,在尋找第二個數(shù)時,只在第一個數(shù)的右側(cè)尋找。

class Solution { public:vector<int> twoSum(vector<int>& numbers, int target) {int n = numbers.size();int flag=0;for(int i=0;i<n;i++){int low = i+1;int high = n-1;while(low<=high){int mid = (high - low) / 2 + low;if (numbers[mid] == target - numbers[i]) {return {i + 1, mid + 1};}else if (numbers[mid] > target - numbers[i]) {high = mid - 1;} else {low = mid + 1;}}}return {};} };


總結(jié):有序序列,查找值固定的數(shù),可以考慮二分查找優(yōu)化

2、雙指針

這是官方題解,和我一開始用的思路是一樣的,即雙指針。

class Solution { public:vector<int> twoSum(vector<int>& numbers, int target) {int low = 0, high = numbers.size() - 1;while (low < high) {int sum = numbers[low] + numbers[high];if (sum == target) {return {low + 1, high + 1};} else if (sum < target) {++low;} else {--high;}}return {-1, -1};} };


而我做的一開始排除一些元素的方法好像沒有對時間有很多優(yōu)化。。。

3、雙指針+二分查找

class Solution { public:vector<int> twoSum(vector<int>& numbers, int target) {int low = 0, high = numbers.size() - 1;while (low <high) {int middle = (low+high)*0.5;//1、目標(biāo)在middle左側(cè),重置highif(numbers[low]+numbers[middle]>target){high =middle-1;}//2、目標(biāo)在middle右側(cè),重置lowelse if(numbers[high]+numbers[middle]<target){low = middle+1;}//3、重置lowelse if(numbers[low]+numbers[high]<target){low++;}//4、重置highelse if(numbers[low]+numbers[high]>target){high--;}//5、sum等于targetelse{return {low+1,high+1}; }}return {0,0};} };


不知道為什么同樣的思路,用java速度可以達(dá)到1ms,而c++卻不行。

總結(jié)

以上是生活随笔為你收集整理的LeetCode 167. 两数之和 II - 输入有序数组 思考分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。