TwoSum
以上是leetcode链接
题目其实很简单,只是使用题中给出的一个int数组,以及一个int型整数,在数组中找两个元素,使其相加等于目标整数。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); i++)//用二重循环进行查找,时间复杂度为O(n^2)
{
for (int j = i + 1; j < nums.size(); j++)
{
if (nums[i] + nums[j] == target)
{
vector<int> vec(2);
vec[0] = i;
vec[1] = j;
return vec;
}
}
}
}
};
我的这个算法有比较大的问题:
(1)使用二重循环来遍历整个数组是没有必要的,凭空增加了不必要的时间复杂度。
(2)过于简单和不动脑筋,查找还有很多其他的方法可以使用,而非只有遍历。
在此贴上leetcode上只需要3ms的优秀代码:
static int x = [](){
std::ios::sync_with_stdio(false);
cin.tie(NULL);
return 0;
}();
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> result;
map<int,int> numNeeded;
std::map<int,int>::iterator it;
int i,targNum, len = nums.size();
for(i = 0; i < len; i++)
{
it = numNeeded.find(nums[i]);
if(it == numNeeded.end())
{
targNum = target - nums[i];
numNeeded.insert(numNeeded.begin(), std::pair<int,int>(targNum,i));
}
else
{
return vector<int> {it->second, i};
}
}
return result;
}
};
关于std::ios::sync_with_stdio()以及cin.tie()这两个函数的使用,参见以下这篇博客的说明。
cin.tie与sync_with_stdio加速输入输出
文中提到,
在ACM里,经常出现数据集超大造成 cin TLE的情况。这时候大部分人(包括原来我也是)认为这是cin的效率不及scanf的错,甚至还上升到C语言和C++语言的执行效率层面的无聊争论。其实像上文所说,这只是C++为了兼容而采取的保守措施。我们可以在IO之前将stdio解除绑定,这样做了之后要注意不要同时混用cout和printf之类。在默认的情况下cin绑定的是cout,每次执行 << 操作符的时候都要调用flush,这样会增加IO负担。可以通过tie(0)(0表示NULL)来解除cin与cout的绑定,进一步加快执行效率。
sync_with_stdio这个函数是一个“是否兼容stdio”的开关,C++为了兼容C,保证程序在使用了std::printf和std::cout的时候不发生混乱,将输出流绑到了一起。
由此可见,sync_with_stdio()与cin.tie()的作用在于对stdio进行解除绑定的操作,增加IO负担的原因在于每次执行<<操作符都被调用的flush。在解绑之后,可以加快执行效率。
3ms的代码中,加快查找速度主要是依靠c++中的关联式容器map。
在map中,根据key值快速查找记录,查找的复杂度是log(n),因此可以较大地加快查找速度。
但是map的的数据结构是采取了键值对的形式,即key-value这种模式,所以在此题当中通过建立map来加速查找,其重点在于如何建立key-value这种对应关系。
源码作者先是建立了一个空的map,for循环中的第一次查找自然是查找不到任何结果的,所以迭代器it会被指向容器尾元素的下一个元素(其实应该是超尾)
然后在接下来if语句的判断条件为it是否指向了numNeeded.end()所返回的值。此时由于map为空,所以numNeeded.end()理应也是超尾,意为没有找到目前所要插入的键值对,key是target与key的差(即targetNum),value为targetNum对应的num[i]的序号。因为对于每一个target,都会有一组特定解在所给出的int数组中。
比如target=3,num[]={1,5,2},那么所建立的map为{<2,0>,<-2,1>},因为在第三次调用find()函数时,返回结果it=begin(),指向了第一个键值对,因而return的vector为<0,2>。