349.两个数组的交集
1)新建一个字典,遍历nums1,填充字典
2)遍历nums2,遇到字典里的值就选出,并从字典中删除
/* 时间复杂度:O(n)
空间复杂度:O(n)
*/
var intersection = function(nums1, nums2) {
const map = new Map()
nums1.forEach(n=>{
map.set(n, true)
})
const res=[]
nums2.forEach(n=>{
if(map.get(n)){
res.push(n)
map.delete(n)
}
})
return res
};
20.有效的括号
之前的思路:利用栈先进后出,遍历字符串,遇到左括号把它压入栈,遇到右括号判断它跟栈顶能否匹配,能的话就把栈顶弹出,否则报错
/** 时间复杂度:O(n)
空间复杂度:O(1) map是O(1)级的常量复杂度,不会随着变量的增加而增加,长度永远都是3(只有3种括号)
*/
var isValid = function(s) {
if(s.length%2===1) return false
const stack=[]
const map=new Map()
map.set('(',')')
map.set('{','}')
map.set('[',']')
for(let i=0;i<s.length;i+=1){
const c=s[i]
if(map.has(c)){ // 只存放(/{/[
stack.push(c)
}else{
// 取出栈顶,判断栈顶是否跟map key对于的value相同,比如}
const t=stack[stack.length-1]
// c跟栈顶的value匹配,就把栈顶弹出
if(map.get(t) === c){
stack.pop()
}else{
return false
}
}
}
return stack.length === 0
};
1.两数之和
思路:用字典建立一个婚姻介绍所,存储相亲者的数字和下标,target为匹配条件,nums为相亲者
1)新建字典
2)nums里的值,组个来mao找对象,没有适合就先登记着,有适合就牵手成功
/** 时间复杂度:O(n) 只有一个for循环,n是nums的长度
* 空间复杂度:O(n) 字典map,可能存储n(nums的长度)个,内存还可以优化,用时间换空间
*/
var twoSum = function(nums, target) {
const map = new Map()
for(let i=0;i<nums.length;i+=1){
const n=nums[i]
const n2 = target - n
if(map.has(n2)){
return [map.get(n2), i ] // 如果存在适合条件的,返回下标
}else{
map.set(n, i)
}
}
};
3. 无重复字符的最长子串
什么是子串? 完整剪切的,连续的字符串某一段
思路:
找出所有不包含重复字符的子串
找出长度最大的那个子串,返回其长度
1)用双指针维护一个滑动窗口,用来剪切子串
2)不断移动右指针,遇到重复字符,就把左指针移动到重复字符的下一位
3)过程中,记录所有窗口的长度,并返回最大值
怎么判断是否重复字符?设置一个map,把当前字符和下标存储到map,遍历的时候判断是否已经存在map
/** 时间复杂度:O(n) n是s的长度
* 空间复杂度:O(m) 字典长度
*/
var lengthOfLongestSubstring = function(s) {
let l=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 // 如果有重复字符,移动左指针
}
res = Math.max(res, r-l+1)
map.set(s[r], r)
}
return res
}
76.最小覆盖子串
思路:
- 用双指针维护一个滑动窗口
- 移到右指针,找到包含T的子串,移动左指针,来减少包含T的子串长度
怎么知道满足需求?当需求字典小于等于0时
怎么拿到需求中最小字符串的?定义一个变量,用来存放
/** 时间复杂度:O(m+n) m是t的长度,n是s的长度
* 空间复杂度:O(m)
*/
var minWindow = function(s, t){
let l=0
let r=0
// 新建一个字典,表示需要子串的个数
const need = new Map() // {'A':1,'B':1,'C':1}
for(let c of t){
need.set(c, need.has(c)? need.get(c)+1:1)
}
// 需求的个数,用来判断是否等于0,等于0表示已经找到所需字符
let needType = need.size
// 记录最小子串,在循环的过程中不断刷新
let res = ''
while(r < s.length){
// 右指针不断移动过程中,获取当前字符
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)// 左开右闭,所以+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
}