目录
第七章 数据结构之“字典”
7.1 字典简介
- 存储唯一值、以键值对的方式存储数据。(映射)
- ES6中用Map表示字典
- 用的操作及代码:增set(),删delete()/clear(), 改set(), 查 get()。
const n = new Map();//实例化一个Map
//增 用编程的方式查看:VScode --> 调试中的(WATCH) --> 搜m.get(),如:m.get(“a”)
m.set(‘a’, ‘aa’);//建立键值对
m.set(‘b’, ‘bb’);//建立键值对//删
m.delete(‘b’);//法一,只删除b
// m.clear();//法二,删除所有的键,即清空字典//改
m.set(‘a’, ‘aaa’);
新建一个字典:
增加set():
用字典的set()方法来往字典中添加键值对,其中a为键,aa为值。
删除delete()/clear():
字典中有两个方法可以进行键值对的删除,其中delete()可以删除某个键值对,clear()是清除字典中的全部键值对。
修改set():
用覆盖的方式进行键值对的改变。
m.set(‘a’, ‘aaa’);
查找 get():
VScode --> 调试中的(WATCH) 用get()方法查找键a的值, 如:m.get(“a”)
7.2 Leetcode:349. 两个数组的交集
解题思路:
- 求nums1和nums2都有的值
- 用字典建立一个映射关系,记录nums1里有的值
- 遍历nums2找出nums1里也有的值
解题步聚:
- 新建一个字典,遍历nums1,填充字典
- 遍历nums2,遇到字典里的值就选出,并从字典中删除
/**
\* @param {number[]} nums1
\* @param {number[]} nums2
\* @return {number[]}
*/
var intersection = function (nums1, nums2) {
const map = new Map();//新建一个字典
nums1.forEach(n => {//遍历nums1里面的值,并把它填充到字典中建立映射关系
map.set(n, true);
});
const res = []; // 声明一个空数组
//遍历nums2里面的值,如果遇到与nums1里面有的值,则把它放到新建数组中,并删除nums2里对应的值。
nums2.forEach(n => {//遍历nums2里面的值
if (map.get(n)) {//如果字典里面有当前这个元素,则
res.push(n);//放到数组中
map.delete(n);//立即删除
}
});
return res;
};
7.3 Leetcode:20,有效的括号
/**
\* @param {string} s
\* @return {boolean}
*/
var isValid = function (s) {
// 先判断字符串的长度是否为奇数,为奇数肯定闭合不了
if (s.length % 2 === 1) {
return false;
}
const stack = [];// 新建一个栈:用数组来模拟这个栈
const map = new Map();// 新建一个字典
map.set('(', ')');//把括号的映射关系存到字典里,新建键值对
map.set('[', ']');
map.set('{', '}');
// 扫描字符串:用一个for循环来扫描
for (let i = 0; i < s.length; i += 1) {//遍历的长度为字符串的长度
const c = s[i]; // 声明一个变量且把遍历的字符存到这个变量C
if (map.has(c)) {//判断字典中是否有当前字符
stack.push(c);//把它推入栈中
}
// 如果遇到右括号就看是否与栈顶元素相匹配
else {
const t = stack[stack.length - 1];// 先获取栈顶元素stack.length-1数组的最后一位
if (map.get(t) = c) { //如果当的栈顶元素等于当前元素:map.get(t) = c
stack.pop(); // 栈里的元素直接出栈
}
else {//否则
return false;
}
}
};
// 判断栈是否为空stack.length === 0
return stack.length === 0;
}
7.4 Leetcode:1.两数之和
解题思路:
- 把nums想象成相亲者
- 把target 想象成匹配条件
- 用字典建立一个婚姻介绍所,存储相亲者的数字和下标。
解题步骤:
- 新建一个字典作为婚姻介绍所。
- mums 里的值,个来介绍所找对象,没有合适的就先登记着,有合适的就牵手成功。
/**
\* @param {number[]} nums
\* @param {number} target
\* @return {number[]}
*/
var twoSum = function (nums, target) {
const map = new Map();// 新建一个字典作为婚姻介绍所
// 遍历nums数组,写一个for循环来遍历
for (let i = 0; i < nums.length; i += 1) {
const n = nums[i];//通过for循环可以拿到nums的每一个值
const n2 = target - n;//通过for循环可以拿到每个值想找的对象的数字
// 问婚姻介绍所有没有我想找的对象
if (map.has(n2)) {
return [map.get(n2), i];//获取它对象的下标,以及它自己的下标
} else {
map.set(n, i);//没找到对象的要在婚姻介绍所来登记信息
}
}
};
//只有一个for循环:时间复杂度为O(n),新建的一个临时字典 const map = new Map();当它足够大时,也为O(n)
7.5 Leetcode:3.无重复字符的最长子串
子串与子序列的区别:
- 子串必须是母串中连续且无重复字符的字符串。(类似于视频剪辑)
- 子序列是有母串的全部字符,但不连续。
解题思路:
- 先找出所有的不包含重复字符的子串
- 找出长度最大那个子串,返回其长度即可
解题步骤:
- 用双指针维护一个滑动窗口,用来剪切子串
- 不断移动右指针,遇到重复字符,就把左指针移动到重复字符的下一位
- 移动过程中,记录所有窗口的长度,并返回最大值
/**
\* @param {string} s
\* @return {number}
*/
var lengthOfLongestSubstring = function (s) {
//用双指针维护一个滑动窗口
let l = 0;//左指针的起始位置是 0
let res = 0;// 记录最大窗口的长度
const map = new Map();//建立一个字典
for (let r = 0; r < s.length; r += 1) {//实现了不断移动右指针
if (map.has(s[r]) && map.get(s[r]) >= l) {//下一次如果发现了这个字符,那么它就是重 复字符
l = map.get(s[r]) + 1;//把l移到重复字符的下一个字符
}
res = Math.max(res, r - l + 1);//新的res, 左指针减右指针加 1
map.set(s[r], r); //把当前的值以及它的下标放到字典里面
}
return res;
};
//只有一个for循环:时间复杂度为O(n),有一个字典const map = new Map();所以空间复杂度为O(m),m是字符串中不重复字符的个数
7.6 Leetcode:76.最小覆盖子串
解题思路:
- 先找出所有的包含T的子串。
- 找出长度最小的那个子串,返回即可。
解题步骤:
- 用双指针维护一个滑动窗口
- 移动右指针,找到包含T的子串,移动左指针,尽量减少包含T的子串的长度
- 循环上述过程,找出包含T的最小子串
/**
\* @param {string} s
\* @param {string} t
\* @return {string}
*/
var minWindow = function (s, t) {
//用双指针维护一个滑动窗口
let l = 0;//左指针的起始位置是 0
let r = 0;//右指针的起始位置是 0
const need = new Map();//新建一个字典,表示子需要的字符及它个数
//用for of遍历字典
for (let c of t) {
need.set(c, need.has(c) ? need.get(c) + 1 : 1);//每个字符以及它的长度
}
let needType = need.size;//需要的类型长度
let res = '';//新建一个字串
//移动右指针r+=1
while (r < s.length) {
const c = s[r];//获取右指针当前字符
// 如果右指针的当前字符在需求列表里面
if (need.has(c)) {
need.set(c, need.get(c) - 1);//不再需要它了
if (need.get(c) === 0) {//如果它需要的某个字符的变量=0
needType -= 1;
}
}
while (needType === 0) {//满足题目要求的情况下
const newRes = s.substring(l, r + 1);
if (!res || newRes.length < res.length) {
res = newRes;
}
const c2 = s[l];//获取左指针当前字符
if (need.has(c2)) {
need.set(c2, need.get(c2) + 1);
//更新needType
if (need.get(c2) === 1) {
needType += 1;
}
}
l += 1;
}
r += 1;
}
return res;
};
7.7 字典总结
- 字典:与集合类似,字典也是一种存储唯一值的数据结构,但他是以键值对的形式来存储。
- ES6中的字典:Map
- 字典的常用操作:键值对的增删改查