⑦ 数据结构之“字典”

一、 理论

1. 字典简介

  • 与集合类似,字典也是一种存储唯一值的数据结构,是以 键值对 的形式存储的
  • es6中有字典Map

1.1 增

const m = new Map()
m.set('a', 'aa')
m.set('b', 'bb')

1.2 删

m.delete('b')
m.clear()

1.3 改

m.set('a', 'aaa')

1.4 查

m.get('a')

二、刷题

1. 两个数组的交集(349)

1.1 题目描述

  • 给定两个数组,编写一个函数来计算它们的交集
  • 说明
    • 输出结果中的每个元素一定是唯一的
    • 我们可以不考虑输出结果的顺序

1.2 解题思路

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

  • 用字典建立一个映射关系,记录nums1里有的值
  • 遍历nums2,找出nums1中有的值

1.3 解题步骤

  • 新建一个字典,遍历nums1,填充字典
  • 遍历nums2,遇到字典里有的值就选出并从字典中删除
function intersection(nums1, nums2) {
  const map = new Map()
  nums1.forEach(item => map.set(item, true))
  const res = []
  nums2.forEach(item => {
    if(map.has(item)) {
      res.push(item)
      map.delete(item)
    }
  })
  return res
}

1.4 时间复杂度&空间复杂度

  • 时间复杂度:O(n+m)
  • 空间复杂度:O(n)

2. 有效的括号(20)

2.1 题目描述

  • 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效
  • 有效字符串需满足:
    • 左括号必须用相同类型的右括号闭合
    • 左括号必须以正确的顺序闭合

2.2 解题思路

输入:s = "()"
输出:true

2.3 解题步骤

function isValid(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++) {
    let c = s[i]
    if(map.has(c)) {
      stack.push(c)
    } else {
      const t = stack[stack.length-1]
      if(map.get(t) === c) {
        stack.pop()
      } else {
        return false
      }
    }
  }
  return stack.length == 0
}

2.4 时间复杂度&空间复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

3. 两数之和(1)

3.1 题目描述

  • 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标
  • 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现
  • 你可以按任意顺序返回答案

3.2 解题思路

输入:nums = [2,7,11,15], target = 9
输出:[0,1]

  • nums相亲者 target匹配条件
  • 用字典建立婚姻介绍所,存储相亲者的数字和下标

3.3 解题步骤

  • 新建字典作为婚姻介绍所
  • 遍历nums写入字典
function twoSum(s) {
  const map = new Map()
  for(let i = 0; i < nums.length; i++) {
    const n = nums[i]
    const n2 = target - n
    if(map.has(n2)) {
      return [map.get(n2), i]
    }
    map.set(n, i)
  }
}

3.4 时间复杂度&空间复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

4. 无重复字符的最长子串(3)

4.1 题目描述

  • 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度

4.2 解题思路

输入:s = "abcabcbb"
输出:3

  • 先找出所有不包含重复字符的子串
  • 找出最长的子串,返回其长度

4.3 解题步骤

  • 双指针维护滑动窗口
  • 不断移动右指针,遇到重复字符,就把左指针移动到重复字符的下一位
  • 移动过程中记录所有窗口的长度并返回最大值
function lengthOfLongestSubstring(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)
  }
}

4.4 时间复杂度&空间复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(m)

5. 最小覆盖子串(76)

5.1 题目描述

  • 给你一个字符串 s 、一个字符串 t
  • 返回 s 中涵盖 t 所有字符的最小子串
  • 如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 ""
  • 注意
    • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量
    • 如果 s 中存在这样的子串,我们保证它是唯一的答案

5.2 解题思路

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"

  • 先找出所有包含t的子串
  • 找出最长的子串,返回其长度

5.3 解题步骤

  • 双指针维护滑动窗口
  • 不断移动右指针,找到包含t的子串,移动左指针,尽量减少包含t的子串的长度
function minWindow(s, t) {
  let l = 0, r = 0
  const need = new Map()
  for(let c of t) {
    need.set(c, need.has(c) ? need.get(c)+1 : 1)
  }
  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--
    }
    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)
        if(need.get(c2) == 1) needType++
      }
      l++
    }
    r++
  }
  return res
}

5.4 时间复杂度&空间复杂度

  • 时间复杂度:O(m+n)
  • 空间复杂度:O(m)

三、总结 -- 技术要点

  • 与集合类似,字典也是一种存储唯一值的数据结构,是以 键值对 的形式存储的
  • es6中有字典Map
  • 字典常用操作:键值对的增删改查
posted on 2022-01-20 15:14  pleaseAnswer  阅读(182)  评论(0编辑  收藏  举报