1.两数之和(two sum)
题目
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
题目分析
题目要求很简单,就是给定一个数组,在给定一个target,返回两个数组中元素的位置使这两个位置对应元素的和为target,
首先,我们想到的最简单粗暴的方法自然是时间复杂度为O(n2),但是这样做显然没什么技术含量嘛,所以考虑下一种情况。
这类题需要遍历整个数组是肯定的,复杂度至少是O(n) ,减少复杂度最简单的方法就是利用哈希表,我们将输入的数组写进哈希表,key是每个元素值,value则是元素的位置。
注意!
我们为什么令** key=元素的值,value=元素的位置**?因为题目中有要求,要求求和的两个数不能重复,也就是即使我输入的数组有2个2,也只能当做1个2处理,所以在哈希表里,保证每一个key不重复出现(即使输入[2,2,5,7,7],在哈希表里也只有[2,5,7]),第二个比较重要的原因就是,当我们查找时,我们是通过key去查找value的,key是元素的值,value是位置,也是最后要返回的,所以,一般是返回值做value,输入值或者查找值做key。
这样,我们通过以空间换取速度的方式,我们可以将查找时间从 O(n) 降低到 O(1)。哈希表正是为此目的而构建的,它支持以近似恒定的时间进行快速查找。我用“近似”来描述,是因为一旦出现冲突,查找用时可能会退化到O(n)。但只要你仔细地挑选哈希函数,在哈希表中进行查找的用时应当被摊销为O(1)。
一个简单的实现使用了两次迭代。在第一次迭代中,我们将每个元素的值和它的索引添加到表中。然后,在第二次迭代中,我们将检查每个元素所对应的目标元素**target-nums[i]**是否存在于表中。注意,该目标元素不能是 nums[i] 本身!
答案
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> m;
vector<int> res;
for (int i = 0; i < nums.size(); ++i) {
m[nums[i]] = i;
}
for (int i = 0; i < nums.size(); ++i) {
int t = target - nums[i];
if (m.count(t) && m[t] != i) {
res.push_back(i);
res.push_back(m[t]);
break;
}
}
return res;
}
};
分析与总结
这是Leetcode第一道题,很简单,但是要想写好也不容易,首先要了解哈希表的结构与用法:
哈希表的原理与数据结构
hash_map基于hash table(哈希表)。 哈希表最大的优点,就是把数据的存储和查找消耗的时间大大降低,几乎可以看成是常数时间;而代价仅仅是消耗比较多的内存。然而在当前可利用内存越来越多的情况下,用空间换时间的做法是值得的。另外,编码比较容易也是它的特点之一。
其基本原理是:使用一个下标范围比较大的数组来存储元素。可以设计一个函数(哈希函数,也叫做散列函数),使得每个元素的关键字都与一个函数值(即数组下标,hash值)相对应,于是用这个数组单元来存储这个元素;也可以简单的理解为,按照关键字为每一个元素“分类”,然后将这个元素存储在相应“类”所对应的地方,称为桶。
但是,不能够保证每个元素的关键字与函数值是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了“冲突”,换句话说,就是把不同的元素分在了相同的“类”之中。 总的来说,“直接定址”与“解决冲突”是哈希表的两大特点。
hash_map,首先分配一大片内存,形成许多桶。是利用hash函数,对key进行映射到不同区域(桶)进行保存。其插入过程是:
- 得到key
- 通过hash函数得到hash值
- 得到桶号(一般都为hash值对桶数求模)
- 存放key和value在桶内。
其取值过程是:
- 得到key
- 通过hash函数得到hash值
- 得到桶号(一般都为hash值对桶数求模)
- 比较桶的内部元素是否与key相等,若都不相等,则没有找到。
- 取出相等的记录的value。
hash_map中直接地址用hash函数生成,解决冲突,用比较函数解决。这里可以看出,如果每个桶内部只有一个元素,那么查找的时候只有一次比较。当许多桶内没有值时,许多查询就会更快了(指查不到的时候).
c++中unordered_map的用法
无序映射是关联容器,用于存储由键值和映射值组合而成的元素,并允许基于键快速检索各个元素。
template < class Key, // unordered_map::key_type
class T, // unordered_map::mapped_type
class Hash = hash<Key>, // unordered_map::hasher
class Pred = equal_to<Key>, // unordered_map::key_equal
class Alloc = allocator< pair<const Key,T> > // unordered_map::allocator_type
> class unordered_map;
STL源码
计划
这是我的第一篇博客,也是第一篇写关于Leetcode的习题,从今天起开始刷题,争取每天一道题吧