难度:简单
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?
1. 循环暴力求解
通过两层for循环遍历各种组合求解,时间复杂度O(n2)O(n^2)O(n2)。用时296ms296 ms296ms。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); i++) {
for (int j = i + 1; j < nums.size(); j++) {
if (nums[i] + nums[j] == target) {
return {i, j};
}
}
}
return {};
}
};
2. 使用哈希查找
使用std::unordered_map<int, int>容器保持已经遍历的数据,再计算新数据时,再容器中查找是否有匹配值,使复杂度降低为O(n)O(n)O(n)。用时8ms8ms8ms。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
std::unordered_map<int, int> map;
for (int i = 0; i < nums.size(); i++) {
int key = target - nums[i];
auto itr = map.find(key);
if (itr == map.end()) {
map.emplace(nums[i], i);
} else {
return {i, itr->second};
}
}
return {};
}
};
3. 官方题解
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hashtable;
for (int i = 0; i < nums.size(); ++i) {
auto it = hashtable.find(target - nums[i]);
if (it != hashtable.end()) {
return {it->second, i};
}
hashtable[nums[i]] = i;
}
return {};
}
};
4. CPP容器[1]
容器(container)是用于存放数据的类模板。可变数组、链表、平衡二叉树等数据结构在STL中都被实现为容器。容器在实例化时,需要指明容器中存放元素的类型,其既可以存放基本的类型(int、double、string等)的变量,也可以存放对象,当元素变量被插入容器中时,实际插入的是变量或者对象的一个复制品。
STL中的许多算法(模板函数),如排序、查找等,在执行过程中会对容器中的元素进行比较,通常使用<<<运算符,因此,被放入容器中的对象所属类最好重载======和<<<运算符,以使得两个对象用======和<<<比较时是有定义的。
容器有顺序容器和关联容器。
4.1 顺序容器
顺序容器有:可变动态数组vector、双端队列deque和双向链表list。是因为元素在容器中的位置和元素的值无关,即容器不是排序的,在指定位置插入,元素就会位于什么位置。
4.2 关联容器
关联容器有:set、multiset、map和multimap。 关联容器内的元素是排序的,在插入元素时,容器会按一定的排序规则将元素放到适当的位置,因此插入元素时不能指定位置。默认情况下,关联容器中的元素是从小到大排序的(或按关键字从小到大排序),而且是用<<<运算符比较元素或者关键字,因此关联容器在查找时具有很好的性能。
4.3 容器适配器
STL在两类容器的基础上屏蔽了一部分功能,突出或者增加了另一部分功能,实现了三种容器适配器:栈stack、队列queue和优先队列priority_queue。
4.4 容器成员函数
所有容器(包括容器适配器)都有的成员函数有两个:
int size();bool empty();
顺序容器和关联容器都有的成员函数:
begin();end();rbegin();rend();erase(...);clear();
顺序容器还有以下常用成员函数:
front();back();push_back();pop_back();insert(...);
5. unordered_map[2]
unordered_map是STL提供的4中无序关联容器的一种,不会像map容器一样对存储的元素或者对象进行排序,因此unordered_map和map只有一点不同,即map容器中数据是有序,而unordered_map中的数据是无序的。由于unordered_map容器底层采用的哈希表存储数据,该结构本身不具有对数据的排序功能,所以容器内部不会自动对存储的键值进行排序。
6. hash_map[3]
hash_map是基于hash table(哈希表)的,哈希表的最大的优点是把数据存储和查找消耗的时间大大降低,几乎是常数时间,而代价是消耗较多的内存,在许多情况小减小耗时更加重要。
其基本原理是,使用一个下标范围较大的数组来存储元素。可以设计一个函数(哈希函数,也叫散列函数),使得每个元素的关键字都与一个函数值(即数组小标,hash值)相对应,于是用这个数组单元来存储这个元素。但是不能保证每个元素的关键字与函数值都是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了"冲突",因此"直接定址"和"解决冲突"是哈希表的两大特点。
hash_map中直接地址使用hash函数生成,解决冲突,用比较函数解决。当关键字生成函数值对应区域只存储一个元素时,查找只有一次比较,因此查询会快很多。由此可见,要实现哈希表,和用户相关的是:hash函数和比较函数,这两个参数是使用hash_map时需要指定的参数。
template <class _Key, class _Tp, class _HashFcn = hash<_Key>,
class _EqualKey = equal_to<_Key>,
class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class hash_map
{
...
}
从STL的声明中可以看出,hash_map的构造函数提供了缺省的hash函数和比较函数,支持基础的数据类型,如下。如果用户使用自定义数据类型时,就必须自定义hash函数和比较函数。
struct hash<char*>
struct hash<const char*>
struct hash<char>
struct hash<unsigned char>
struct hash<signed char>
struct hash<short>
struct hash<unsigned short>
struct hash<int>
struct hash<unsigned int>
struct hash<long>
struct hash<unsigned long>
7. reference
[1] http://c.biancheng.net/view/331.html
[2] http://c.biancheng.net/view/7231.html
[3] https://blog.youkuaiyun.com/yousss/article/details/79541543
3096

被折叠的 条评论
为什么被折叠?



