每周完成一个ARTS:(Algorithm、Review、Tip、Share, ARTS)
- Algorithm: 每周至少做一个 leetcode 的算法题
- Review: 阅读并点评至少一篇英文技术文章
- Tip: 学习至少一个技术技巧
- Share: 分享一篇有观点和思考的技术文章
题目相关
【题目】原题链接
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
【难度】Easy
Solution
1. 暴力求解
最直接的方法,进行暴力求解,进行两次遍历。代码如下:
该代码性能表现:(性能低,耗时长)
- Your memory usage beats 92.16 % of cpp submissions.
- Runtime: 408 ms
- Memory Usage: 9.3 MB
vector<int> twoSum_lowPerformance(vector<int> &nums, int target)
{
int nFirstPos = 0;
int nSecondPos = 0;
int nLen = nums.size();
for (int i = 0; i < nLen; i++)
{
for (int j = 0; j < nLen; j++)
{
//i,j不能一样
if (i != j)
{
int temp = nums[i] + nums[j];
if (temp == target)
{
if (i < j)
{
nFirstPos = i;
nSecondPos = j;
break;
}
else if (i > j)
{
nFirstPos = j;
nSecondPos = i;
break;
}
}
}
}
}
vector<int> vecRet;
if (nFirstPos != nSecondPos)
{
vecRet.push_back(nFirstPos);
vecRet.push_back(nSecondPos);
return vecRet;
}
else
{
return vecRet;
}
}
2. 暴力求解方法改进
上面的暴力求解中,其实在进行两次遍历时有很多可以优化的地方,比如i从1开始,进行逐个相加比较,此时应该从第二个元素开始进行比较,第一个没必要了(题目要求:同一个元素不要使用两次)。代码如下:
该代码性能表现:(性能低,耗时长)
- Your runtime beats 40.17 % of cpp submissions.
- Runtime: 112 ms
- Memory Usage: 9.4 MB
//target - first,然后在已有的数据中遍历查找
vector<int> twoSum(vector<int> &nums, int target)
{
int nFirstPos = 0;
int nSecondPos = 0;
int nLen = nums.size();
vector<int> vecRet;
for (int i = 0; i < nLen; i++)
{
int temp = target - nums[i];
for (int j = i + 1; j < nLen; j++)
{
// printf("i = %d,j = %d,temp = %d, tartget = %d\n", i, j, temp, target);
if (temp == nums[j])
{
nFirstPos = i;
nSecondPos = j;
//break; //仅有一个break只能跳出一个for循环,外围的for不能跳出
// 所以这里要么使用goto,要么直接return。
// 由于return报错,所以采用goto方式
if (nFirstPos != nSecondPos)
{
vecRet.push_back(nFirstPos);
vecRet.push_back(nSecondPos);
goto end;
}
}
}
}
end:
return vecRet;
}
3. 不可行的方案
通过 方案2 获知,该问题可以看成在序列中进行查找「target - first」,所以想到了二分查找,二分查找需要有序才有效,题目中没有相关有序字段,所以想到了排序。。。
先看代码,后面有分析
//先排序
//target - first,然后在已有的数据中进行二分查找
// 不能这么操作,不然顺序已经改变了,后面再检测到的下标已经无效
vector<int> twoSum_err(vector<int> &nums, int target)
{
int nFirstPos = 0;
int nSecondPos = 0;
int nLen = nums.size();
sort(nums.begin(), nums.end(), less<int>());
for (int i = 0; i < nLen; i++)
{
int temp = target - nums[i];
std::cout << "temp = " << temp << endl;
//二分查找?
vector<int>::iterator index = lower_bound(nums.begin(), nums.end(), temp);
if (index != nums.end())
{
nFirstPos = i;
nSecondPos = index - nums.begin();
break;
}
}
vector<int> vecRet;
if (nFirstPos != nSecondPos)
{
vecRet.push_back(nFirstPos);
vecRet.push_back(nSecondPos);
return vecRet;
}
else
{
return vecRet;
}
}
上面的代码不可行,这样能提到查找效率,但是经过排序后,原序列中的顺序已经改变了,后面返回的下标是最新的,而不是之前的,所以该方案不可行。
后记
改进的方案 在CPP中才排到40.17 %,说明还有更好的方案,没看解析,继续思考最优方案,看看自己能想到哪些?。