问题描述
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例
给定 nums=[2,7,11,15],target=9nums = [2, 7, 11, 15], target = 9nums=[2,7,11,15],target=9
因为 nums[0]+nums[1]=2+7=9nums[0] + nums[1] = 2 + 7 = 9nums[0]+nums[1]=2+7=9
所以返回 [0,1][0, 1][0,1]
map的使用方法
1、map是标准的关联式容器,在#include<map>头文件中。一个map是一个键值对序列,即(key,value)对。它提供基于key的快速检索能力。
#include<map>
#include<algorithm> //这个头文件最好也加上
map<int,string> mymap1,mymap2;
2、map中key值是唯一的。集合中的元素按一定的顺序排列。元素插入过程是按排序规则插入,所以不能指定插入位置。
mymap1.insert(pair<int,string>(1,"C++"));
mymap2.insert(pair<int,string>(2,"Java"));
也可以用insert函数插入value_type数据
mymap1.insert(map<int,string>::value_type(1,"C++"));
mymap2.insert(map<int,string>::value_type(2,"Java"));
3、map的具体实现采用红黑树变体的平衡二叉树的数据结构。在插入操作和删除操作上比vector快。
4、map可以直接存取key所对应的value,支持[]操作符,如map[key]=value。
mymap1[1] = "C++";
mymap2[2] = "Java";
以上三种用法,都可以实现数据的插入,但还是有所区别,第一种和第二种是一样的,用insert函数插入数据在数据的插入上涉及到集合的唯一性这个概念,即当map中有这个关键字时,insert操作是插入数据不了的,但是用数组方式可以覆盖以前该关键字对应的值。
5、查找map中的元素,第一种,用count函数来判定关键字是否存在,其缺点是无法定位数据出现位置。由于map的一对一的映射关系,就决定了count函数的返回值只有两个,存在返回1,不存在返回0;
mymap1.count(1);//存在key为1的键值,返回1,不存在,返回0
第二种:用find函数来定位数据出现位置,它返回的是数据位置的一个迭代器,如果没有找到map中的数据,返回的迭代器为map中的end()。
mymap1.find(1); // 返回key为1的数值的迭代器的位置 不存在 返回end()
下面将分别从调用两遍哈希算法、调用一遍哈希算法、暴力求解、C语言解法这四种方法来解答此题。
代码实现
1、使用两遍hash算法求解
先将每个元素的键值对赋值好再进行比较,由于题目要求返回两个数的数组下标,所以nums数组的元素值为map中的key值,元素所对应的数组下标为map中的value值,这与正常思路是相反的。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int ,int> mymap;
for(int i = 0; i < nums.size(); i++)
{
mymap[nums[i]] = i; // 反过来存 和正常思路相反
}
for(int i = 0; i < nums.size(); i++)
{
if(mymap.find(target - nums[i]) != mymap.end() && mymap[target - nums[i]] != i)
{
return {i, mymap[target - nums[i]]};
}
}
return {};
}
};
2、使用一遍hash算法求解
在mymap已有的赋值元素中找到与nums[i]nums[i]nums[i]之和为targettargettarget的值,因为指针iii一直在mymap所有元素的后序,所以返回的数组下标序列中,iii应该在后面。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int,int> mymap;
for(int i=0;i<nums.size();i++)
{
if(mymap.find(target-nums[i])!=mymap.end())//mymap中存在对应的键值
return {mymap[target-nums[i]],i};
mymap[nums[i]]=i; //向map中添加元素
}
return {};
}
};
这两种方法本质上没有明显的区别,时间复杂度均为O(n)O(n)O(n)。
3、暴力求解
该方法实现的时间复杂度要高与前两种,为O(n2)O(n^2)O(n2),但是思考起来比较容易。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for(int i=0; i<nums.size() - 1; i++)
for(int j = i + 1; j < len; j++)
if(nums[i] + nums[j] == target)
return {i,j};
return {};
}
};
4、C语言方法
这是C语言的解答,时间复杂度为O(n2)O(n^2)O(n2)。
int* twoSum(int* nums, int numsSize, int target) {
int i,j;
int *result=NULL;
for(i = 0; i < numsSize - 1; i++)
{
for(j = i + 1; j < numsSize; j++)
{
if(nums[i] + nums[j] == target)
{
result = (int*)malloc(sizeof(int) * 2);
result[0] = i;
result[1] = j;
return result;
}
}
}
return result;
}
永远不要说自己有多么爱动脑,学习多么刻苦,因为网上总会有比你更新颖的,思路更清晰的解答方法,他们会比你更刻苦或者是更聪明,甚至是两者兼备。