字典
- 与集合类似,字典也是一种存储唯一值的数据结构,但它是以 键值对 (集合是 [值 值])的形式来存储
- ES6 中有字典,名为
Map
- 字典的常用操作:键值对的增删改查
LeetCode:349 两个数组的交集
给定两个数组 nums1
和 nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的
解题思路:
- 求
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 => {
map.set(n, true);
});
const res = [];
nums2.forEach(m => {
if(map.get(m)) {
res.push(m);
map.delete(m);
}
});
return res;
};
时间复杂度:O(n + m)
空间复杂度:O(n)
LeetCode:20. 有效的括号
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = "()"
输出:true
示例 2:
输入:s = "()[]{}"
输出:true
示例 3:
输入:s = "(]"
输出:false
用字典简化相关操作
/**
* @param {string} s
* @return {boolean}
*/
var isValid = function(s) {
if (s.length % 2 === 1) return false;
let stack = [];
const map = new Map();
map.set('(', ')');
map.set('{', '}');
map.set('[', ']');
for (let i of s) {
// map.has - 判断 key 是否在 map 中
if (map.has(i)) {
stack.push(i)
} else {
let top = stack[stack.length - 1];
if (map.get(top) === i) {
stack.pop()
} else {
return false
}
}
}
return stack.length === 0;
};
时间复杂度:O(n)
空间复杂度:O(n)
LeetCode:1. 两数之和
给定一个整数数组 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]
解题思路:
nums
逐个遍历target
是匹配条件- 建立一个字典,存储相亲者的数字和下标
解题步骤:
- 新建一个字典
nums
里面的值,逐个匹配,没有合适的就先放在字典中,有合适的就输出
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
let map = new Map();
for(let i = 0; i < nums.length; i++) {
if(map.has(target - nums[i])) {
return [map.get(target - nums[i]), i]
}else {
map.set(nums[i], i);
}
}
};
时间复杂度:O(n)
空间复杂度:O(n)
LeetCode:3. 无重复字符的最长子串
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串(完整的剪切)。
解题思路:
- 先找出所有的不包含重复字符的子串
- 找出长度最大的那个子串,返回其长度即可
解题步骤:
- 用双指针维护一个滑动窗口,用来剪切子串
- 不断移动右指针,遇到重复字符,就把左指针移动到重复字符的下一位
/**
* @param {stringtring} string
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let l = 0;
let res = 0;
const map = new Map();
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;
};
时间复杂度:O(n)
空间复杂度:O(m) 其中 m
是字符串中不重复字符个数
LeetCode:76. 最小覆盖子串
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意:
- 对于
t
中重复字符,我们寻找的子字符串中该字符数量必须不少于t
中该字符数量。 - 如果
s
中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
示例 2:
输入:s = "a", t = "a"
输出:"a"
解释:整个字符串 s 是最小覆盖子串。
示例 3:
输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中, 因此没有符合条件的子字符串,返回空字符串。
解题思路:
- 先找出所有包含
T
的子串 - 找出长度最小的那个子串,返回即可
解题步骤:
- 用双指针维护一个滑动窗口
- 移动右指针,找到包含
T
的子串后,再移动左指针,尽量减少包含T
的子串的长度 - 循环上述过程,找到最小子串
/**
* @param {string} s
* @param {string} t
* @return {string}
*/
var minWindow = function(s, t) {
let l = 0;
let r = 0;
let need = new Map();
for (let c of t) {
// 存储 t 中的字符以及个数
need.set(c, need.has(c) ? need.get(c) + 1 : 1)
}
let needType = need.size;
let res = '';
while (r < s.length) {
// 移动右指针,找到包含 T 的子串
const c = s[r];
if (need.has(c)) {
need.set(c, need.get(c) - 1);
if (need.get(c) === 0) needType -= 1;
}
while (needType === 0) {
const newRes = s.substring(l, r + 1);
if (!res || newRes.length < res.length) res = newRes;
// 移动左指针,尽量减少包含 T 的子串的长度
const c2 = s[l];
if (need.has(c2)) {
need.set(c2, need.get(c2) + 1);
if (need.get(c2) === 1) needType += 1;
}
l += 1;
}
r += 1;
}
return res;
};
时间复杂度:O(m+n) 其中 m
是 t
的长度, n
是 s
的长度
空间复杂度:O(m)