Leetcode:1.两数之和
很明显暴力的解法是两层for循环查找,时间复杂度是O(n^2)。
当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。
本题就需要一个集合来存放我们遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是 是否出现在这个集合。
那么我们就应该想到使用哈希法了。哈希表能将查找操作的时间复杂度从 O (n) 降至 O (1),从而大幅优化整体效率。
因为本地,我们不仅要知道元素有没有遍历过,还有知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。
std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。
同理,std::map 和std::multimap 的key也是有序的
这道题目中并不需要key有序,选择std::unordered_map 效率更高!
map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下表,这样才能找到与当前元素相匹配的(也就是相加等于target)
接下来是map中key和value分别表示什么。
这道题 我们需要 给出一个元素,判断这个元素是否出现过,如果出现过,返回这个元素的下标。
那么判断元素是否出现,这个元素就要作为key,所以数组中的元素作为key,有key对应的就是value,value用来存下标。
所以 map中的存储结构为 {key:数据元素,value:数组元素对应的下表}。
在遍历数组的时候,只需要向map去查询是否有和目前遍历元素比配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。
class Solution {
public:vector<int> twoSum(vector<int>& nums, int target) {vector<int> result;unordered_map<int, int> m;for (int i = 0; i < nums.size(); i++) {int tar = target - nums[i];auto it = m.find(tar);if (it != m.end()) {result.push_back(it->second);result.push_back(i);return result;}m.insert(make_pair(nums[i], i));}return result;}
};
用哈希表缓存已遍历的元素和下标,每次查找 tar
只需 O (1) 时间,整体从 O (n²) 降至 O (n)。
本质上就是用空间换时间,通过额外的哈希表存储信息,避免重复遍历。
哈希表在此处的作用:
快速映射:将「元素值」与「下标」绑定,通过值能直接找到对应的下标(无需遍历)。
实时缓存:边遍历边存储已访问的元素,确保每次查找的都是「之前出现过的元素」(避免重复计算)。
在编程问题中,当需要快速判断元素是否存在、高效统计元素出现的频率或次数,或是要在不同元素间建立键值对应关系以简化查找,以及希望通过优化嵌套循环中的查找操作来降低整体时间复杂度,且对元素顺序无严格要求时,通常适合使用哈希表,其核心优势在于以空间换时间,通过键值对的映射关系实现高效的查找、插入和删除操作,能有效解决各类依赖快速映射和统计的问题。实现数据高效的 CRUD 操作。