LeetCode1 Two Sum/3Sum/3Sum Closest **

一:Two Sum

题目:

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;}};

此外,如果这里有多个满足a+b= target 怎么办,比如[-4,-1,0,0,0,2,2,3] target = 2, 如何求出多个且互相独立的<-1,3>与[0,2]呢,

此时我们在判断出a[i]+a[j] == target的时候,还需要判断a[i] == a[i-1] && a[j]==a[j+1] 是否成立,成立的话,则不不进行加入,直接i++,j–

代码如下:

void twoSumAll(vector<int> &num, int target, vector<vector<int> > &result){ //找到a+b == target并且unique 假设num已经排序好O(N)int i = 0, j = num.size()-1;while(i < j){int a = num[i];int b = num[j];if(a + b == target){// 如果重复则 i++ ,j– 如 [-1 0 0 2 2 4] target = 2if((i-1 >= 0 && num[i-1]==a) && (j+1 < num.size()-1 && num[j] == b)){i++;j–;}else{ // 不重复 独一无二的vector<int> v;v.push_back(a);v.push_back(b);result.push_back(v);i++;j–;}}else if(a+b < target) i++;// 小于 i++ 增大和else j–; //大于 j– 降低和 }}

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,6if(j != i){// 注意这里判断下 以防止如[3,2,4] 6 3+3=6 没有判断则输出1 1vec.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,此时结点多了速度也慢,以空间换时间,查找速度更快

二: 3Sum

题目:

有本钱耍个性,离开睁眼闭眼看见的城市,逃离身边的纷纷扰扰,

LeetCode1 Two Sum/3Sum/3Sum Closest **

相关文章:

你感兴趣的文章:

标签云: