Map哈希映射
哈希映射
是用于存储 (key, value)
键值对的一种实现。
使用哈希映射的第一个场景是,我们需要更多的信息
,而不仅仅是键。然后通过哈希映射建立密钥与信息之间的映射关系
。
让我们来看一个例子:
给定一个整数数组,返回两个数字的索引,使它们相加得到特定目标。
在这个例子中,如果我们只想在有解决方案时返回 true,我们可以使用哈希集合来存储迭代数组时的所有值,并检查 target - current_value 是否在哈希集合中。
但是,我们被要求返回更多信息,这意味着我们不仅关心值,还关心索引。我们不仅需要存储数字作为键,还需要存储索引作为值。因此,我们应该使用哈希映射而不是哈希集合。
模板
/*
* Template for using hash map to find duplicates.
* Replace ReturnType with the actual type of your return value.
*/
ReturnType aggregateByKey_hashmap(List<Type>& keys) {
// Replace Type and InfoType with actual type of your key and value
Map<Type, InfoType> hashmap = new HashMap<>();
for (Type key : keys) {
if (hashmap.containsKey(key)) {
if (hashmap.get(key) satisfies the requirement) {
return needed_information;
}
}
// Value can be any information you needed (e.g. index)
hashmap.put(key, value);
}
return needed_information;
}
两个数组的交集 II
题目描述:
(力扣链接🔗)
题目分析:
使用map来进行查重,此时选择map因为需要记录次数。也可以使用双指针法。
代码:
解法一:
/**
* hash表(使用map) 时间复杂度:O(m+n) 空间复杂度:O(min(m,n))
* @param nums1
* @param nums2
* @return
*/
public int[] intersect(int[] nums1, int[] nums2) {
Map<Object, Integer> map = new HashMap<>();
List<Integer> list = new ArrayList<>();
// 将数字保存在map中,value存储次数
for (int i = 0; i < nums2.length; i++) {
map.put(nums2[i], map.getOrDefault(nums2[i], 0) + 1);
}
for (int i = 0; i < nums1.length; i++) {
// map中存在且不为0
if (map.containsKey(nums1[i]) && map.get(nums1[i]) != 0) {
map.put(nums1[i], map.getOrDefault(nums1[i], 0) - 1);
list.add(nums1[i]);
}
}
// 转化为int数组
int[] ints = new int[list.size()];
int index = 0;
for(Integer value : list) {
ints[index++] = value;
}
return ints;
}
解法二:
思路为2个数组分别使用2个指针进行遍历,在判断是否相等,不相等则移动指针。
/**
* 排序 + 双指针
*
* @param nums1
* @param nums2
* @return
*/
public int[] intersect(int[] nums1, int[] nums2) {
// 将其进行排序,分别使用2个指针进行遍历
Arrays.sort(nums1);
Arrays.sort(nums2);
int index = 0, index1 = 0, index2 = 0;
int[] ints = new int[Math.min(nums1.length, nums2.length)]; // 用来保存交集
// 2个指针一直向后判断,直到其中一个指针遍历完毕
while (index1 < nums1.length && index2 < nums2.length) {
// 谁小就向后移动
if (nums1[index1] < nums2[index2]) {
index1++;
} else if (nums1[index1] > nums2[index2]) {
index2++;
} else { // 相等赋值进去即可
ints[index] = nums1[index1];
index++;
index1++;
index2++;
}
}
// 将后面为0的截取掉
return Arrays.copyOfRange(ints, 0, index);
}
字母异位词
题目描述
力扣链接🔗
题目分析:
可以知道每个字符串字母都一样,但是顺序不同,可以先将字符串进行排序,在放到map中查找是否存在重复。此时map中的value不需要存储次数或者索引,所以我们可以使用value来存储复合条件的字符串集合。
代码:
class Solution {
/**
* map解法
* @param strs
* @return
*/
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<Object, List<String>> map = new HashMap<>();
List<List<String>> list = new ArrayList<>();
for (int i = 0; i < strs.length; i++) {
String str = sort(strs[i]);
if (map.containsKey(str)) {
map.get(str).add(strs[i]);
} else {
List<String> stringList = new ArrayList<>();
stringList.add(strs[i]);
map.put(str, stringList);
}
}
// 遍历将map中的value全部取出来
for (Map.Entry<Object, List<String>> entry : map.entrySet()) {
list.add(entry.getValue());
}
return list;
}
// 将其进行排序
public String sort(String str) {
char[] record = str.toCharArray();
Arrays.sort(record);
return String.valueOf(record);
}
}
两数之和
题目描述:
力扣链接🔗
题目分析:
- 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
- set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。
使用map可以存储索引值。
代码:
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
// 相减后,判断后边是否存在temp即可
int temp = target - nums[i];
if (map.containsKey(temp)) {
return new int[]{map.get(temp), i};
}
// 将索引作为value
map.put(nums[i], i);
}
return new int[]{};
}
}
四数相加II
题目描述:
力扣链接🔗
题目分析:
- 首先定义 一个unordered_map,key放a和b两数之和,value 放a和b两数之和出现的次数。
- 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
- 定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
- 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
- 最后返回统计值 count 就可以了
巧妙的通过先计算2个数组中所有总和,并使用map来记录次数,在判断相加是否为0时,将0减去相加的数,即可转化为查重。
代码:
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer, Integer> map = new HashMap<>();
int total = 0;
for (int num1 : nums1) {
for (int num2 : nums2) {
// 将2数之和放入map,value保存出现的次数
int temp = num1 + num2;
map.put(temp, map.getOrDefault(temp, 0) + 1);
}
}
for (int num3 : nums3) {
for (int num4 : nums4) {
// 在man中找相加等于0的数
int temp = 0 - (num3 + num4);
if (map.containsKey(temp)) {
total += map.get(temp);
}
}
}
return total;
}
}