-
字典是一种以键值对的形式来存储唯一值的数据结构
-
ES6 中有字典,名为 Map
-
字典的常用操作:键值对的增删改查
-
如需更详细了解 Map 可看我这篇文章:ES6 Set和Map数据结构以及Symbol数据类型 - 掘金 (juejin.cn)
1、LeetCode: 349.两个数组的交集
解题思路:
- 求 nums1 和 nums2 都有的值
- 用字典建立一个映射关系,记录 nums1 里有的值
- 遍历 nums2,找出 nums1 里也有的值
解题步骤:
- 新建一个字典,遍历 nums1,填充字典
- 遍历 nums2,遇到字典里的值就选出,并从字典中删除
// 时间复杂度 O(m + n) m为nums1长度 n为nums2长度
// 空间复杂度 O(m) m为交集的数组长度
const intersection = function(nums1, nums2) {
const map = new Map();
nums1.forEach(n1 => {
map.set(n1, true);
})
const result = [];
nums2.forEach(n2 => {
if(map.get(n2)) {
result.push(n2);
map.delete(n2);
}
})
return result;
};
2、LeetCode: 20.有效的括号
const isValid = s => {
// 不是偶数,直接返回
if (s.length % 2 !== 0) return false;
const stack = [];
const map = new Map();
map.set("(", ")");
map.set("{", "}");
map.set("[", "]");
for (let i = 0; i < s.length; i++) {
const item = s[i];
if (map.has(item)) {
stack.push(item);
} else {
const top = stack[stack.length - 1];
if (map.get(top) === item) {
stack.pop();
} else {
return false;
}
}
}
return stack.length === 0;
};
3、LeetCode: 1. 两数之和
解题思路:
- 把 nums 想象成相亲者
- 把 target 想象成匹配条件
- 用字典建立一个婚姻介绍所,存储相亲者的数字和下标
解题步骤:
- 新建—个字典作为婚姻介绍所
- 遍历 nums,让 nums 里的值,逐个来介绍所找对象,没有合适的就先登记着,有合适的就牵手成功
// 时间复杂度O(n) n为nums的length
// 空间复杂度O(n) map对象存储的值
const twoSum = function(nums, target) {
const map = new Map();
for(let i = 0; i < nums.length; i++) {
const item = nums[i];
const targetNumber = target - item;
if(map.has(targetNumber)) {
return [map.get(targetNumber), i];
}else {
map.set(item, i);
}
}
};
4、LeetCode: 3.无重复字符的最长子串
解题思路:
- 先找出所有的不包含重复字符的子串
- 找出长度最大那个子串,返回其长度即可
解题步骤:
- 用双指针维护一个滑动窗口,用来剪切子串
- 不断移动右指针,遇到重复字符,就把左指针移动到重复字符的下一位
- 过程中,记录所有窗口的长度,并返回最大值
// 时间复杂度 O(n) n为s字符串长度
// 空间复杂度 O(m) 字典的长度,长度为字符串里不重复字符的个数
const lengthOfLongestSubstring = function(s) {
// 左指针
let l = 0;
const map = new Map();
let res = 0;
for(let r = 0; r < s.length; r++) {
// 判断字典里是否有重复字符 且 该字符必须在滑动窗口内
if(map.has(s[r]) && map.get(s[r]) >= l) {
l = map.get(s[r]) + 1;
}
// 记录每个窗口最大值
res = Math.max(res, r - l + 1);
map.set(s[r], r);
}
return res;
};
5、LeetCode: 76.最小覆盖子串
解题思路:
- 先找出所有的包含T的子串
- 找出长度最小那个子串,返回即可
解题步骤:
- 用双指针维护一个滑动窗口
- 移动右指针,找到包含T的子串,移动左指针,尽量减少包含T的子串的长度
- 循环上述过程,找出包含T的最小子串
// 输入:s = "ADOBECODEBANC", t = "ABC"
// 输出:"BANC"
// 时间复杂度 O(m + n) m是t的长度 n是s的长度
// 空间复杂度 O(k) k是字符串中不重复字符的个数
const minWindow = function(s, t) {
// 定义双指针维护一个滑动窗口
let l = 0;
let r = 0;
const map = new Map();
// 遍历t字符串,生成需要查找字符串map
for(let key of t) {
map.set(key, map.has(key) ? map.get(key) + 1 : 1);
}
let needType = map.size;
// // 记录最小子串
let res = "";
// 移动右指针
while(r < s.length) {
const item = s[r];
// 查找到遍历的值,减少其需要的数量
if(map.has(item)) {
map.set(item, map.get(item) - 1);
if(map.get(item) === 0) needType -= 1;
}
// 当查找到了所有需要的值needType为0,就说明找到了一个子串(不一定是最小子串)
while(needType === 0) {
// 取出符合要求的最新子串
const newRes = s.substring(l, r + 1);
// 如果结果子串更大,则替换成当前最新的子串
if(!res || res.length > newRes.length) {
res = newRes;
}
// 从左指针处获取值
const leftItem = s[l];
// 如果字典里有值,而下面左指针会+1后,就会增加需要的值
if(map.has(leftItem)) {
map.set(leftItem, map.get(leftItem) + 1);
if(map.get(leftItem) === 1) needType += 1;
}
l += 1;
}
r += 1;
}
return res;
};