Given an array of integers, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution.
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
链接:https://leetcode.com/problems/two-sum/
分析:此题有三种解法,时间复杂度也是逐渐降低的,第一种方法是暴力,所需时间为O(N^2),第二种方法是排序,后两边往中间扫描,时间复杂度为排序的时间O(NlgN);第三种方法是用hash_map, 所需的时间复杂度为O(N),it is amazing!!
1:暴力法
暴力法即通过两个循环判断两个数的和是否为target, 时间复杂度为O(N),在leetcode上过不了,会TLE
class Solution { public: vector<int> twoSum(vector<int> &numbers, int target) { vector<int> vec; for(int i =0; i < numbers.size()-1; i++){ for(int j = i+1; j < numbers.size(); j++){ if((numbers[i] + numbers[j]) == target){ vec.push_back(i); vec.push_back(j); return vec; } } } } };2:排序+两边扫描
由于我们要求数组中元素的小标,排序必然破坏这点,所以需要一个结构体来保存数组中的值和小标,然后依据结构体中的value进行排序;排序后可以通过两个指针,分别指向首i和尾j,如果和等于target,则找到;如果大于target,则将j--以降低和大小;否则小于则i++增大和,时间复杂度为O(NlgN+N)= O(lgN).
相对于第一种方法,时间复杂度降低了,但是空间复杂度增加到了O(N),可以说是以空间换时间吧。从两端往中间扫描的思想很重要,或者二分,上一道题也用到了这个思想,
// 结构体 为了保存下标 struct sNode{ int value; int index; sNode(int v, int i){ this->value = v; this->index = i; } }; bool cmp(sNode s1, sNode s2){ // 按值排序 return s1.value < s2.value; } class Solution { public: vector<int> twoSum(vector<int> &numbers, int target) { vector<sNode> vec; vector<int> result; for(int i = 0; i < numbers.size(); i++){ vec.push_back(sNode(numbers[i], i)); } sort(vec.begin(), vec.end(), cmp); int i = 0, j = vec.size()-1; while(i != j){ int sum = vec[i].value + vec[j].value; if(sum == target){ // 等于则找到 if(vec[i].index < vec[j].index){ result.push_back(vec[i].index+1); result.push_back(vec[j].index+1); } else{ result.push_back(vec[j].index+1); result.push_back(vec[i].index+1); } break; } else if(sum < target){ // 小于 i++ 增大和 i++; } else j--; // 大于 j-- 降低和 } return result; } };3:hash_map
只需扫描一次,每次扫描的时候判断是否在hash_map中,如果不在加入hash_map表中,接着判断target-该元素是否在hash表中,如果在,则找到,注意这里有两点:(1)防止如[3,2,6] 6,,3+3=6 两次hash要判断下标是否相同 (2)如果有重复元素也是可以的,因为即使重复元素没有加入hash_map中,它还是会找target-该元素 是否存在hash_map中的, 如[3,4,3] 6 也是可以满足的。
相对于第一种方法,以空间换时间,但是时间复杂度只需要O(N)了。
// hash_map 时间复杂度降维O(n) class Solution { public: vector<int> twoSum(vector<int> &numbers, int target) { vector<int> vec; map<int, int> hmap; for(int i =0; i < numbers.size(); i++){ if(!hmap.count(numbers[i])){ hmap.insert(pair<int, int>(numbers[i], i)); } if(hmap.count(target-numbers[i])){ // 此时如果数组中元素重复了 没有加入到hash表中,但是结果仍然是正确的 int j = hmap[target-numbers[i]]; // 如3,4,3,6 if(j != i){ // 注意这里判断下 以防止如[3,2,4] 6 3+3=6 没有判断则输出1 1 vec.push_back(j+1); vec.push_back(i+1); return vec; } } } return vec; } };由于LeetCode上没有包含hash_map这个STL容器,故这里用了map,map是基于RBTree的,hash_map基于hash_table,
区别:set和map底层数据结构是rbtree,而hash_map和hash_set底层是hashtable,不具有自动排序的功能了,但是当数据量很大的时候,只能用hash_map或者hash_set,因为map或者set都是基于rbtree,此时结点多了速度也慢,以空间换时间,查找速度更快
原文地址:http://blog.csdn.net/lu597203933/article/details/44858905