给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例: 给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
C++
遍历两遍数组 寻找结果
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
bool notFound = true;
int i=-1;
int j=0;
while(notFound == true)
{// 找到时候跳出
i++;
j=0;
if(i==nums.size())
{//遍历结束跳出
std::cout << "not found";
notFound = false;
}
else
{
for(j; j<nums.size();j++)
{
if(j!=i)
{
if((nums[i]+nums[j])== target)
{ notFound = false;
break;
}
}
}
}
}
vector<int> answer;
answer.push_back(i);
answer.push_back(j);
return answer;
}
};
代码执行结果
执行用时 : 396 ms 在所有 C++ 提交中击败了 13.36% 的用户
内存消耗 : 9.2 MB , 在所有 C++ 提交中击败了 79.86% 的用户
存在的问题: while 循环跳出优化 / for循环跳出优化
优化循环的结构和跳出条件
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
bool notFound = true;
int i=-1;
int j=0;
while(notFound == true && i!=nums.size())
{
i++;
//j从i+1 的位置开始可以避免重复计算 例如避免计算 i=0 j=1 和 i=1 j=1 的情况
for(j=i+1; j<nums.size();j++)
{
if((nums[i]+nums[j])== target)
{
notFound = false;
break;
}
}
}
vector<int> answer;
answer.push_back(i);
answer.push_back(j);
return answer;
}
};
执行结果:
执行用时 : 244 ms, 在所有 C++ 提交中击败了 31.21% 的用户
内存消耗 : 9.1 MB , 在所有 C++ 提交中击败了 96.52% 的用户
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
bool notFound = true;
vector<int> answer;
int i=-1;
int j=0;
while(notFound == true && i!=nums.size())
{
i++;
for(j=i+1; j<nums.size();j++)
{
if((nums[i]+nums[j])== target)
{
notFound = false;
answer.push_back(i);//避免再一次读取i/j的值
answer.push_back(j);
break;
}
}
}
return answer;
}
};
代码执行结果
执行用时 : 184 ms, 在所有 C++ 提交中击败了48.23%的用户
内存消耗 : 9.2 MB , 在所有 C++ 提交中击败了 91.94%的用户
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
// 优化循环不设置 flag 同时减少运行时间和内存消耗
for(int i = 0; i<nums.size();i++)
{
for(int j=i+1; j<nums.size();j++)
{
if((nums[i]+nums[j])== target)
{
return {i,j}; // 直接返回结果 减少内存消耗
}
}
}
throw "Not found!"; // 使用Exception 提高代码的健壮性
}
};
代码执行结果
执行用时 : 172 ms, 在所有 C++ 提交中击败了49.52%的用户
内存消耗 : 9.1 MB , 在所有 C++ 提交中击败了92.59%的用户
另外一个小的优化: 1. 使用 一个常数代替 num.size(), 牺牲内存获取执行上的一点点速度
这差不多是暴力法能做到的极致了
map类和 hashmap 的查找效率比较高,可以换成这两种
c++ map类参考资料 https://blog.csdn.net/xywlpo/article/details/6545594
c++ unordered_map (哈希表) 类参考资料 https://zh.cppreference.com/w/cpp/container/unordered_map
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> numsHash;
for(int i = 0 ; i < nums.size() ; i ++){
numsHash[nums[i]] = i;
} //初始化hash表
for(int i = 0 ; i < nums.size() ; i++)
{
auto index = numsHash.find(target-nums[i]);//返回查找到元素的iterator,如未查找到,返回end() 疑问: 寻找的是键还是值?
if(index!=numsHash.end() && index->second!=i)
{
return {i,index->second}; //
}
}
return {0,0};
}
};
该方法有一遍初始化 O(n) 和一遍hash的查找O(1) 时间复杂度低,但是空间复杂度高
代码执行结果
执行用时 : 8ms, 在所有 C++ 提交中击败了98.71%的用户
内存消耗 : 10.4 MB , 在所有 C++ 提交中击败了16.92%的用户
范例
执行用时为 4 ms 的
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
//时间复杂度n,空间复杂度n
// 还是使用哈希表,但不在一开始就insert,而是在迭代过程中insert,只需查找一次哈希表
map<int, int> myMap;
// 初始化一个大小是2,值为-1的vector容器
vector<int> result(2, -1);
for (int i = 0; i < nums.size(); i++) {
// 前面的值在哈希表中,相当于从后往前找,所以这样命名
int secondNum = nums[i];
int firstNum = target - secondNum;
// 当前值nums[i]还不在哈希表中,不用判断目标值是否本身
if (myMap.count(firstNum) > 0) {
result[0] = myMap[firstNum];
result[1] = i;
break;
}
// 没找到就放入哈希表中
myMap.insert(make_pair(secondNum, i));
}
return result;
}
};
在我自己基础上优化的代码
有个问题是根据结果来看,这段代码的优化效果为负 XD
执行用时 :12 ms, 在所有 C++ 提交中击败了92.50%的用户
内存消耗 :10.1 MB, 在所有 C++ 提交中击败了35.89%的用户
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> numsHash;
for(int i = 0 ; i < nums.size() ; i++)
{
auto index = numsHash.find(target-nums[i]);//返回查找到元素的iterator,如未查找到,返回end() 疑问: 寻找的是键还是值?
if(index==numsHash.end())
{
numsHash[nums[i]]=i; // 没找到
}
else if(index->second!=i)
{
return {i,index->second}; //返回位置
}
else{
numsHash[nums[i]]=i; // 找到了,但是是同一个值
}
}
return {0,0};
}
};