1.题目要求
给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。
示例:
2.解法一:暴力法(for*for,O(n*n))
分析:因为题目假设“每个输入只对应一种答案,且相同的元素不能被重复利用”,这就降低了难度。
暴力法:使用两次for循环。第一个for循环依次遍历一次数组,每次执行过程中选取了一个数组元素nums[i], 再for循环遍历nums[i]后面的所有元素,假设取到的元素为nums[j](其中,i+1=< j <=size-1,size为所传入数组的元素个数 )同时比较过程中取到的两个元素的和算法等于target,因为每种输入只对应一种答案,且相同元素不同被重复利用,因此找到了就可以直接返回[i,j];没有找到符合题意的解,就返回[-1,-1]。
//完整代码
#include <iostream> #include <vector> using namespace std; class Solution { public: vector<int> twoSum(vector<int>& nums, int target){}; }; vector<int> twoSum(vector<int>& nums, int target) { vector<int> result; int surplus; //余数 for (int i = 0; i != nums.size() - 1; ++i) { surplus = target - nums[i];//余数 for (int j = i + 1; j != nums.size(); ++j) { if (surplus == nums[j]) { result.push_back(i); result.push_back(j); return result; } } }
//找不到则返回[-1,-1] result.push_back(-1); result.push_back(-1); return result; } int main() { vector<int> arr = { 2, 7, 11, 15 }; int val = 30; cout << "[" << twoSum(arr,val)[0]<< "," << twoSum(arr,val)[1] << "]" << endl; return 0; }
3.解法二:hash查找(复杂度O(1))
(1)数值的唯一性
map和set两种容器的底层结构都是红黑树,所以容器中不会出现相同的元素,
因此count()的结果只能为0和1,可以以此来判断键值元素是否存在(当然也可以使用find()方法判断键值是否存在)。
拿map<key,value>举例
count( ) 方法的返回值是布尔值, 返回1,键值元素存在;返回0,键值元素不存在
find( ) 方法返回值是一个迭代器,成功,返回迭代器指向要查找的元素;失败,返回的迭代器指向end。
//哈希函数使用示例 #include<iostream> #include<map> #include<string> using namespace std; int main() { map<int,string> maps; if(maps.find(1)==maps.end()) { cout<<"没有1这个元素"<<endl; } if(maps.count(1)==0) { cout<<"没有1这个元素"<<endl; } //添加元素1 maps[1]="one"; if(maps.find(1)!=maps.end()) { cout<<"有1这个元素"<<endl; } if(maps.count(1)) { cout<<"有1这个元素"<<endl; } return 0; }
//两数之和-哈希查找 #include <iostream> #include <vector> #include <map> using namespace std; class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { vector<int> result; //map<key,value> 哈希表的映射 map<int, int> temp_map; for (int i = 0; i != nums.size(); ++i) temp_map[nums[i]] = i; for (int i = 0; i != nums.size(); ++i) { int surplus = target - nums[i]; //值为surplus的元素存在,且不为nums[i]本身 if (temp_map.count(surplus) != 0 && temp_map[surplus] != i) { result.push_back(i); result.push_back(temp_map[surplus]); return result; } } result.push_back(-1); result.push_back(-1); return result; } }; int main() { vector<int> arr = { 2, 7, 11, 15 }; int val = 30; Solution test; cout << "[" << test.twoSum(arr, val)[0] << "," << test.twoSum(arr, val)[1] << "]" << endl; return 0; }
4.举一反三!!!
扩展思考:给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
注意:这里不加上题中的限制条件。返回所有符合题意的两数的下标,相同的元素可以重复利用。但是不能是同一个元素与自身组合,这样就不符合两数的概念了。
给定 nums = [2, 7, 2,2,11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 nums[1] + nums[2] = 7 + 2 = 9
nums[1] + nums[3] = 7 + 2 = 9 所以返回 [0, 1],[1,2],[1,3]
修改题目的要求后,解题的大体思路是一致的,只是再返回数据的时候,处理上有些差异。因为Leetcode上没有提供这种情况下的测试用例,因此,下面给出的代码只是参考(单一用例跑通)。
另外,由于笔者对hash表的使用尚不熟练,这个给出的解法是采用暴力法。
#include <iostream> #include <vector> using namespace std; class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { vector<int> result; int surplus; //余数 for (int i = 0; i != nums.size() - 1; ++i) { surplus = target - nums[i];//余数 for (int j = i + 1; j != nums.size(); ++j) { if (surplus == nums[j]) { result.push_back(i); result.push_back(j); } } } ////修改返回值的次序 //找不到则返回[-1,-1] if (result.size() == 0) { result.push_back(-1); result.push_back(-1); return result; } return result; } }; int main() { vector<int> arr = { 2, 7, 2, 2, 11, 15 }; int val = 9; Solution test; ////修改了输出条件 for (int i = 0; i != test.twoSum(arr, val).size(); i += 2) { cout << "[" << test.twoSum(arr, val)[i] << "," << test.twoSum(arr, val)[i+1] << "]" << “ ”; } cout << endl; return 0; }
参考资料:
1:https://www.cnblogs.com/bewolf/p/5146787.html 谈谈map中的count方法
2:https://www.cnblogs.com/grandyang/p/4130379.html [LeetCode] Two Sum 两数之和