【前端算法系列】字典

博客围绕JavaScript展开,讲解了多道数据结构与算法题目。包括两个数组的交集、有效的括号、两数之和等题,介绍了使用字典、栈、双指针维护滑动窗口等方法解题,还提及判断重复字符等技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值