LeetCode01-两数之和
1.两数之和:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
解题思路1:
暴力寻找,双重for循环,时间复杂度高O(n^2)。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int>ans;
int len=nums.size();
for(int i=0;i<len;i++){
for(int j=i+1;j<len;j++){
if(nums[i]+nums[j]==target){
ans.push_back(i);
ans.push_back(j);
return ans;
}
}
}
return ans;
}
};
解题思路2:
用STL的map标记之前已经有的数位置,时间复杂度O(nlogn),因为map查找复杂度为logn。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int>ans;
ans.clear();
map<int,int>mp;
mp.clear();
int len=nums.size();
for(int i=0;i<len;i++){
int tmp=target-nums[i];
if(mp[tmp]!=0){
ans.push_back(mp[tmp]-1); //减1和加1是因为下标从0开始的,然而计数要从1开始
ans.push_back(i);
return ans;
}
mp[nums[i]]=i+1;
}
return ans;
}
};
解题思路3:
手动写二分,时间复杂度O(nlogn)。因为二分要排序,所以要自己建立一个结构体来标记之前的编号,不过还是写得有点复杂了。
typedef struct num{
int num;
int id;
}NUM;
bool cmp(NUM a,NUM b){
return a.num<b.num;
}
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int len = nums.size();
//用v数组来代替nums数组,v[i].id代表第i个数对应于原nums数组的第几个数
vector<NUM>v;
for(int i=0;i<len;i++){
NUM tmp;
tmp.num = nums.at(i);
tmp.id = i;
v.push_back(tmp);
}
sort(v.begin(),v.end(),cmp);
vector<int>ans;
for(int i=0;i<len;i++){
int x = target - v.at(i).num;
int ll=0,rr=len-1,mid;
while(ll<=rr){
mid = (ll+rr)>>1;
//相等并且找到的不是自己符合条件返回
if(v.at(mid).num==x && v.at(mid).id!=v.at(i).id){
if(v.at(mid).id<v.at(i).id){
ans.push_back(v.at(mid).id);
ans.push_back(v.at(i).id);
}else{
ans.push_back(v.at(i).id);
ans.push_back(v.at(mid).id);
}
return ans;
}
else if(v.at(mid).num>x)
rr = mid-1;
else
ll = mid+1;
}
}
return ans;
}
};
解题思路4:
在解三数之和时,学习到了一种新的解题想法,在对于有序数组时,我们可以利用双指针来找到两个数的和满足某个值。利用双指针l,r,如果当前和大于target,则只能移动r,因为移动l,当前和只会越来越大。如果当前和小于target,则只能移动l,因为移动r,当前和只会越来越小。所以双指针往中间扫描就行。
在排序过程中需要记录之前的位置,所有利用结构体排序,由于本题只存在唯一解,找到即可以返回。
class Solution {
struct Node {
int val;
int id;
friend bool operator<(struct Node x,struct Node y) {
if(x.val==y.val)
return x.id<y.id;
return x.val<y.val;
}
}a[10005];
public:
vector<int> twoSum(vector<int>& nums, int target) {
int len=nums.size();
for(int i=0;i<len;i++) {
a[i].val=nums[i];
a[i].id=i;
}
sort(a,a+len);
vector<int>ans;
int l=0,r=len-1;
while(l<r) {
if(a[l].val+a[r].val==target) {
ans.push_back(min(a[l].id,a[r].id));
ans.push_back(max(a[l].id,a[r].id));
break;
}
if(l<r&&l!=len-1&&a[l].val+a[r].val<target)
l++;
else if(l<r&&r!=0&&a[l].val+a[r].val>target)
r--;
}
return ans;
}
};