Leetcode-JS解法-哈希表相关题目

135 阅读5分钟

前言

最近在刷题准备秋招,自己也总结了一些leetcode题目的JS解法,刷题我是看大佬的题解,这里只是简单梳理下思路,想看详细题解的可以进到对应的题目里面去看,每道题我都贴上对应的leetcode地址,这一期是哈希表的相关题目,后面会持续更新,感兴趣可以关注一下!

存在重复元素

简-存在重复元素-217

217. 存在重复元素 - 力扣(LeetCode)

使用set判断是否有重复元素

/**
 * @param {number[]} nums
 * @return {boolean}
 */
var containsDuplicate = function(nums) {
  const set = new Set()
  for(let num of nums){
      if(set.has(num)){
          return true
      }
      set.add(num)
  }
  return false
};

简-存在重复元素2-219

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

需要用到下标,所以使用map进行存储

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {boolean}
 */
var containsNearbyDuplicate = function(nums, k) {
  const map=new Map()
  for(let i=0;i<nums.length;i++){
    // map中存在这个值,且两个相等值的下标差<k
    if(map.has(nums[i]) && (i-map.get(nums[i])<=k)){
      return true
    }else{
      map.set(nums[i],i)
    }
  }
  return false
};

简-扑克牌中的顺子-剑指o61

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

思路:

方法1:set+遍历

  • 通过set判断是否有重复牌
  • 同时通过两个变量来储存最小最大值
/**
 * @param {number[]} nums
 * @return {boolean}
 */
var isStraight = function(nums) {
    const set = new Set()
    let max=0,min=14
    for(let i=0;i<nums.length;i++){
        // 遇到大小王则跳过
        if(nums[i] === 0) continue
        max=Math.max(max,nums[i])
        min=Math.min(min,nums[i])
        // 若有重复,提前返回false
        if(set.has(nums[i])) return false
        set.add(nums[i])
    }
    // 最大牌 - 最小牌 < 5 则可构成顺子
    return max-min<5
};

方法2: 排序+遍历

  • 将数组进行排序,最大值就为最后一个
  • 通过一个变量来记录大小王的数量,最小值即为nums[joker]
/**
 * @param {number[]} nums
 * @return {boolean}
 */
var isStraight = function(nums) {
    // 记录大小王数量
    let joker = 0
    // 排序
    nums=nums.sort(function(a,b){
        return a-b
    })
    for(let i=0;i<nums.length;i++){
        // 遇到大小王
        if(nums[i] === 0) joker++
        // 若有重复,提前返回false
        else if(nums[i] == nums[i+1]) return false
    }
    // 最大牌 - 最小牌 < 5 则可构成顺子
    return nums[4] - nums[joker]<5
};

简-第一个只出现一次的字符-剑指o50

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

思路:使用哈希表记录每一个数的情况,未重复的标记为true,最后再遍历一遍哈希表,输出第一个为true的数

/**
 * @param {string} s
 * @return {character}
 */
var firstUniqChar = function(s) {
    if(s.length==0){
        return ' '
    }
    const map = new Map()
    // 记录每个字符的情况,未重复的标记为true
    for(let item of s){
        map.set(item,!map.has(item))
    }
    // 遍历哈希表,返回第一个为true的元素
    for(let m of map){
        if(m[1]){
            return m[0]
        }
    }
    return ' '
};

简-两个数组的交集-349

349. 两个数组的交集 - 力扣(LeetCode)

思路:使用set存储num2,再对num1中元素进行验证

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function(nums1, nums2) {
  const result = new Set()
  const set = new Set(nums2)//数组转set

  for(num of nums1){
    // 数组搜索值,复杂度O(n)
    // Set Map -.has 复杂度O(1)
    // 如果有交集
    if(set.has(num)){
      result.add(num)
    }
  }
  return  Array.from(result)
};

中-重复的DNA序列-187

187. 重复的DNA序列 - 力扣(LeetCode)

思路-哈希表:

使用哈希表统计每个字符串的出现次数,返回大于2的

/**
 * @param {string} s
 * @return {string[]}
 */
var findRepeatedDnaSequences = function(s) {
  const map = new Map()
  const result = []
  for(let i=0;i+10<=s.length;i++){
    const dna = s.substring(i,i+10)
    if(map.get(dna)===undefined){
      map.set(dna,1)
    }else if(map.get(dna) === 1){
      map.set(dna,2)
      result.push(dna)
    }else{
      map.set(dna,map.get(dna)+1)
    }
  }
  return result
};

思路-set

这道题可以不使用哈希表,只用set存储判断是否重复就行

/**
 * @param {string} s
 * @return {string[]}
 */
var findRepeatedDnaSequences = function(s) {
  const set = new Set()
  const result = new Set()
  for(let i=0;i+10<=s.length;i++){
    const dna = s.substring(i,i+10)
    if(set.has(dna)){
      result.add(dna)
    }else{
      set.add(dna)
    }
      
  }
  return Array.from(result)
};

简-有效的字母异位词-242

力扣

思路:

  1. 如果两个数组长度不一致,则返回false
  2. 创建一个map,用来存储每个字符出现的次数
    • 对于第一个单词的每个字母(即s[i]),在map里出现的次数+1
    • 对于第二个单词的每个字母(即t[i]),在map里出现的次数-1
  3. 遍历完成后,检查map里的每一个字母的出现次数是不是0,如果有一个非0的字母,则返回false,否则返回true
/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function(s, t) {
    if(s.length!==t.length){
      return false
    }
    const map = new Map()
    for(let i=0;i<s.length;i++){
      if(map.has(s[i])){
        map.set(s[i],map.get(s[i])+1)
      }else{
        map.set(s[i],1)
      }

      if(map.has(t[i])){
        map.set(t[i],map.get(t[i])-1)
      }else{
        map.set(t[i],-1)
      }
    }

    for(const letter of map){
      if(letter[1]!==0){
        return false
      }
    }
    return true
};

中-字母异位词分组-49

力扣

将组合单词的字母相同的排在一起

思路

  1. 检查是否为空数组
  2. 建立一个长度为26的数组,起始值为0
  3. 遍历所有的字符串,将字母的出现频率放到数组的对应位置里(利用ascil码)
  4. 遍历数组,按照相同字母出现频率进行分组归类(使用hashMap)
  5. 遍历map,将结果返回

具体代码

/**
 * @param {string[]} strs
 * @return {string[][]}
 */
var groupAnagrams = function(strs) {
    if(strs.length === 0){
      return []
    }
    const map=new Map()
    for(const str of strs){
      // 创建一个长度为26的数组,起始值为0
      const characters= Array(26).fill(0)
      // 遍历所有字符串,将字母的出现频率放到数组的对应位置里
      for(let i=0;i<str.length;i++){
        // 利用ascil码判断是哪个字母
        const ascli=str.charCodeAt(i)-97
        characters[ascli]++
      }
      // console.log('characters',characters)
      const key=characters.join()//转为字符串
      // console.log('key',key)
      // 如果存在相同字母
      if(map.has(key)){
        // 分组拼接数组
        // map.set(key,map.get(key).push(str))
        map.set(key,[...map.get(key),str])
      }else{
        // 不存在相同字母则新建一个
        map.set(key,[str])
      }
    }

    const result = []
    // 遍历map
    for(const arr of map){
      // console.log('arr',arr)
      // [ '1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0', [ 'bat' ] ]
      // console.log('arr[1]',arr[1])
      // [ 'bat' ]
      // arr[1]是value值
      result.push(arr[1])
    }
    console.log('result',result)
    return result
};

const strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
groupAnagrams(strs)

后续还有哈希表相关题目会继续补充的,欢迎在评论区交流