leetcode 之哈希

159 阅读2分钟

“哈希表” 考察频率很高!

哈希是典型的以空间换时间的数据结构,它的插入/删除/查找的时间复杂度都是 O(1)。而空间复杂度则取决于存储的数据。例如有M个键,那么可以达到 O(M) 的空间复杂度。??

3. 无重复字符的最长子串:滑动窗口 + 重复值在窗口内判断

题目3. 无重复字符的最长子串

要求一次遍历!是频率最高的题目。

  1. 用双指针lefti维护滑动窗口,用来保存无重复字符的子串。
  2. 哈希表保存 {字符 :对应下标}注意判断重复值是否在窗口内(大于等于)!
const lengthOfLongestSubstring = (s) => {
  const map = new Map();
  let maxLength = 0;  // 最长子串的长度
  let left = 0; // 滑动窗口左边界
  
  for (let i = 0; i < s.length; i++) {
    if (map.has(s[i]) && map.get(s[i]) >= left) { // 重复字符的索引大于或等于左指针
      left = map.get(s[i]) + 1; // 举例就能理解
    }
    maxLength = Math.max(maxLength, i - left + 1);
    map.set(s[i], i);
  }
  
  return maxLength;
}

时间复杂度:O(n)。哈希表插入和搜索的时间复杂度O(1)。

空间复杂度:O(m)。m 是哈希存储键的个数,最多是字符串s的大小。

1. 两数之和

题目1. 两数之和

创建哈希表保存 {元素:元素下标} 。遍历数组判断哈希表中是否有等于target - nums[i]的值,如果有则返回两个下标,否则就更新哈希表。

const twoSum = (nums, target) => {
  const 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)。主要是哈希表的开销

349. 两个数组的交集:Set

题目349. 两个数组的交集

  • 借助Set去重,因为Set的成员值是唯一不重复的。
  • 优化点:遍历长度较小的集合。
const intersection = (nums1, nums2) => {
  const set1 = new Set(nums1); // [...set]
  const set2 = new Set(nums2);
  const res = [];
  
  // if (set1.size > set2.size) { // 遍历较小的集合
  //   [set1, set2] = [set2, set1]; 
  // }
  
  for (let item of set1) {
    if (set2.has(item)) {
      res.push(item);
    } 
  }
  return res;
};

时间复杂度:O(m + n)。其中两个new Set储存两个数组中的元素需要 O(m + n) 的时间,然后遍历较小的集合并进行判断需要 O(min(m, n)),因此总时间复杂度是 O(m + n)。

空间复杂度:O(m + n)。主要取决于两个 set 集合。