第68篇 LeetCode题目练习(一) 1.两数之和
1.题目描述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。 |
输入:nums = [3,2,4], target = 6 输出:[1,2] |
示例 3:
输入:nums = [3,3], target = 6 输出:[0,1] |
提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2.暴力解法-双重for循环
一看到题目,我首先想到的是双重for循环,而且还没有任何优化的双重for循环。
2.1.思路
先从数组中取出一个数nums[i],然后从这个数的下一个数nums[j]开始,依次相加判断是否有nums[i] + nums[j] == target,有就存储这两个数的坐标。
2.2.算法
Algorithm twoSum(nums[0...n],target)
//描述:给定一个整数数组 nums 和一个整数目标值 target,在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
//输入:数组nums,目标值target
//输出:数组nums中和为目标值 target 的那两个整数对应的下标。
result<-null
for i <- 0 to n
for j <- i + 1 to n
if nums[i] + nums[j] = target
result[0] <- i
result[1] <- j
return result
2.3.代码
vector<int> twoSum(vector<int>& nums, int target)
{
vector<int>result;
for(int i = 0;i < nums.size() ;i++)
{
for(int j = i+1;j < nums.size();j++)
{
if(nums[i]+nums[j]==target)
{
result.push_back(i);
result.push_back(j);
}
}
}
return result;
}
毫无疑问,超时了,因为就算找到了之后,我还在判断,所以就得超时,那得改进,在找到的时候跳出循环就好了。
2.4.改进一-break
** 算法**
Algorithm twoSum(nums[0...n],target)
//描述:给定一个整数数组 nums 和一个整数目标值 target,在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
//输入:数组nums,目标值target
//输出:数组nums中和为目标值 target 的那两个整数对应的下标。
result<-null
for i <- 0 to n
for j <- i + 1 to n
if nums[i] + nums[j] = target
result[0] <- i
result[1] <- j
break
return result
代码
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> res;
for(int i = 0;i < nums.size();i++){
for(int j = i + 1;j < nums.size();j++){
if(nums[i] + nums[j] == target){
res.insert(res.end(),i);
res.insert(res.end(),j);
break;
}
}
}
return res;
}
结果
通过了,但是时间复杂度是O(n^2),因此太慢了。
2.5.改进二-迭代器
给的数组是vector,我就想能不能用迭代器,然后使用库函数find去进行查找,获得nums[i]之后,从数组里面查找是否存在(target - nums[i]),存在即找到结果,数的位置可以通过函数distance计算出和数组第一个数的距离,即位置。
算法
Algorithm twoSum(nums[0...n],target)
//描述:给定一个整数数组 nums 和一个整数目标值 target,在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
//输入:数组nums,目标值target
//输出:数组nums中和为目标值 target 的那两个整数对应的下标。
result<-null
for it <- nums.begin() to nums.end()
ret = find(nums.begin(),nums.end(),target - *it)
if ret != nums.end()
result[0] <- distance(nums.begin(),it);
result[1] <- distance(nums.begin(),ret);
break
return result
** 代码**
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ans;
for(vector<int>::iterator it = nums.begin();it != nums.end();it++){
vector<int>::iterator ret = find(nums.begin(),nums.end(),target - *it);
if(ret != nums.end() && ret != it){
ans.push_back(distance(nums.begin(),it));
ans.push_back(distance(nums.begin(),ret));
break;
}
}
return ans;
}
结果
可以看到减少了1/4的时间,但是还不是很好的,因为进行了重复的操作,所以很不友好,再改。
2.6.改进二-迭代器2
ret = find(nums.begin(),nums.end(),target - *it)
忘了是从j+1开始的,所以把查询的开始位置改一下。从it + 1的位置开始。
算法
Algorithm twoSum(nums[0...n],target)
//描述:给定一个整数数组 nums 和一个整数目标值 target,在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
//输入:数组nums,目标值target
//输出:数组nums中和为目标值 target 的那两个整数对应的下标。
result<-null
for it <- nums.begin() to nums.end()
ret = find(it + 1,nums.end(),target - *it)
if ret != nums.end()
result[0] <- distance(nums.begin(),it);
result[1] <- distance(nums.begin(),ret);
break
return result
代码
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ans;
for(vector<int>::iterator it = nums.begin();it != nums.end();it++){
vector<int>::iterator ret = find(nums.begin(),nums.end(),target - *it);
if(ret != nums.end() && ret != it){
ans.push_back(distance(nums.begin(),it));
ans.push_back(distance(nums.begin(),ret));
break;
}
}
return ans;
}
结果
又减少了一半的时间,是最坏时间的1/8了。
但是看了题解还有更牛的,
时间是最坏情况的1/50,
3.哈希表map
为了能用这个做出来,我用一个星期大概浏览了STL中的容器部分,算法部分只会for_each、find、distance,其他的没用上
map是保存键值对的,如(12,34)、(“a”,13),里面的两个数据可以是任意类型,前面是键,后面是值,而且可以通过键访问值
如:map[12] = 34,map[“a”] = 13,a = map[12] -> a为34
还有通过count函数可以查找是否有对应的键
如:a.count(target-nums[i])
那么对于这个题就可以通过保存nums[i]和i,然后获取到nums[i]后,就可以查找(target - nums[i])这个键是否存在(存在返回值大于0),存在即找到答案。不存在则保存nums[i]和i。
算法
Algorithm twoSum(nums[0...n],target)
//描述:给定一个整数数组 nums 和一个整数目标值 target,在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
//输入:数组nums,目标值target
//输出:数组nums中和为目标值 target 的那两个整数对应的下标。
result<-null
m <- null
for i <- 0 to n
if m.count(target - nums[i]) > 0
result[0] <- i
result[1] <- m[target - nums[i]]
break
m[nums[i]] <- i
return result
代码
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ans;
map<int,int> m;
for(int i=0;i<nums.size();i++){
if(m.count(target-nums[i]) > 0) {
ans.push_back(i);
ans.push_back(m[target-nums[i]]);
break;
}
m[nums[i]] = i;
}
return ans;
}
结果
4.结语
想要时间快,如果没有好的算法,那就尽量减少操作次数,减少重复的操作。