Leetcode算法题:哈希表篇

6/13/2023 算法刷题集

# 1. 有效的字母异位词(简单) (opens new window)

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意: 若 s 和 t **中每个字符出现的次数都相同,则称 s 和 t **互为字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

输入: s = "rat", t = "car"
输出: false

# 思路

使用 哈希表 , 记录第一个字符串的所有字符的个数,然后迭代第二个字符串,动态减少 哈希表 中记录的字符个数,若字符不存在(字符个数已为0或压根就没存在过)返回 false,否则返回 true

# JS

// 1. 哈希表
var isAnagram = function(s, t) {
  if (s.length != t.length) return false // 长度不同,肯定false

  let map = new Map()
  for (let w of s) {
    map.set(w, map.get(w) ? map.get(w) + 1 : 1)
  }
  for (let w of t) {
    if (!map.get(w)) return false // 一语双关:undefined 和 0
    map.set(w, map.get(w) - 1)
  }
  return true
}

// 2. unicode数组
var isAnagram = function (s, t) {
  if (s.length !== t.length) return false

  let arr = new Array(26).fill(0)
  let base = 'a'.charCodeAt() // 基准 a-z 0-26

  for (let item of s) arr[item.charCodeAt() - base]++
  for (let item of t) if (!arr[item.charCodeAt() - base]--) return false
  
  return true
};

# Golang

// 1. 哈希表
func isAnagram(s string, t string) bool {
  if len(s) != len(t) {
    return false
  }

  m := map[rune]int{}
  for _, w := range s {
    m[w]++
  }
  for _, w := range t {
    if (m[w] == 0) {
      return false
    }
    m[w]--
  }
  return true
}

// 2. unicode数组(go数组是值,而非指针)
func isAnagram(s string, t string) bool {
  if len(s) != len(t) {
    return false
  }

  var arr1, arr2 [26]int
  for _, w := range s {
    arr1[w - 'a']++
  }
  for _, w := range t {
    arr2[w - 'a']++
  }
  return arr1 == arr2
}

# 2. 两个数组的交集(简单) (opens new window)

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

示例 1:

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

示例 2:

输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [9,4]
解释: [4,9] 也是可通过的

# 思路

使用 setmap

# JS

var intersection = function(nums1, nums2) {
  let ret = new Set()
  let set = new Set(nums1)
  for (let n of nums2) {
    if (set.has(n)) ret.add(n)
  }
  return [...ret]
}

# Golang

func intersection(nums1 []int, nums2 []int) []int {
  var set = make(map[int]bool, 0) // 使用map模拟set
  var ret = make([]int, 0)

  for _, n := range nums1 {
    if set[n] {
      continue
    }
    set[n] = true
  }
  for _, n := range nums2 {
    if !set[n] {
      continue
    }
    ret = append(ret, n)
    delete(set, n)
  }
  return ret
}

# 3. 快乐数(简单) (opens new window)

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

输入: n = 19
输出: true
解释: 12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

输入: n = 2
输出: false

# JS

var isHappy = function(n) {
  let map = new Map()
  
  for (n = getDigitSum(n); n != 1; n = getDigitSum(n)) {
    if (map.has(n)) return false
    map.set(n, true)
  }
  return true
}

function getDigitSum(n) {
  let ret = 0
  while (n) {
    ret += (n % 10) * (n % 10)
    n = n / 10 | 0
  }
  return ret
}

# Golang

func isHappy(n int) bool {
  var m = make(map[int]bool, 0)
  
  for n = getDigitSum(n); n != 1; n = getDigitSum(n) {
    if (m[n]) {
       return false
    }
    m[n] = true
  }

  return true
}
func getDigitSum(n int) int {
  var ret = 0

  for n != 0 {
    ret += (n % 10) * (n % 10)
    n = n / 10
  }

  return ret
}

# 4. 两数之和(简单) (opens new window)

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入: nums = [2,7,11,15], target = 9
输出: [0,1]
解释: 因为 nums[0] + nums[1] == 9 ,返回 [0, 1]

示例 2:

输入: nums = [3,2,4], target = 6
输出: [1,2]

示例 3:

输入: nums = [3,3], target = 6
输出: [0,1]

# JS

var twoSum = function (nums, target) {
  let map = new Map()
  for (let i = 0; i < nums.length; i++) {
    if (map.has(target - nums[i])) return [map.get(target - nums[i]), i]
    map.set(nums[i], i)
  }
  return []
}

# Golang

func twoSum(nums []int, target int) []int {
  var m = make(map[int]int)
  for idx, n := range nums {
    if preIdx, ok := m[target - n]; ok {
      return []int{preIdx, idx}
    }
    m[n] = idx
  }
  return []int{}
}

# 5. 四数相加 II(中等) (opens new window)

给你四个整数数组 nums1nums2nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

  • 0 <= i, j, k, l < n
  • nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

示例 1:

输入: nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出: 2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0

示例 2:

输入: nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
输出: 1

# JS

var fourSumCount = function (nums1, nums2, nums3, nums4) {
  let ret = 0
  let map = new Map()
  for (let n of nums1) {
    for (let m of nums2) {
      map.set(m + n, map.get(m + n) ? map.get(m + n) + 1 : 1)
    }
  }
  for (let n of nums3) {
    for(let m of nums4) {
      if (map.has(-n-m)) ret += map.get(-m-n)
    }
  }
  return ret
}

# Golang

func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
  var ret = 0
  var m = make(map[int]int)
  for _, a := range nums1 {
    for _, b:= range nums2 {
      m[a + b]++
    } 
  }
  for _, a := range nums3 {
    for _, b:= range nums4 {
      ret += m[-a-b]
    } 
  }
 
  return ret
}

# 6. 三数之和(中等) (opens new window)

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意: 答案中不可以包含重复的三元组。

示例 1:

输入: nums = [-1,0,1,2,-1,-4]
输出: [[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1][-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入: nums = [0,1,1]
输出: []
解释: 唯一可能的三元组和不为 0

示例 3:

输入: nums = [0,0,0]
输出: [[0,0,0]]
解释: 唯一可能的三元组和为 0

# 思路

没有什么思路,有的是套路

# JS

var threeSum = function (nums) {
  nums.sort((a, b) => a - b)
  let ret = []
  for (let i = 0; i < nums.length - 2; i++) {
    if (nums[i] + nums[i + 1] + nums[i + 2] > 0) break // 剪枝
    if (i > 0 && nums[i] == nums[i - 1]) continue // 去重

    let l = i + 1, r = nums.length - 1, sum = 0
    while (l < r) {
      sum = nums[i] + nums[l] + nums[r]
      if (sum < 0) {
        l++
        continue
      }
      if (sum > 0) {
        r--
        continue
      }
      ret.push([nums[i], nums[l], nums[r]])
      while (l < r && nums[l] == nums[++l]) continue // 去重
      while (l < r && nums[r] == nums[--r]) continue // 去重
    }
  }

  return ret
}

# Golang

func threeSum(nums []int) [][]int {
  sort.Ints(nums)
  var ret = [][]int{}
  for i := 0; i < len(nums) - 2; i++ {
    if (nums[i] + nums[i+1] + nums[i+2] > 0) {
      break
    }
    if (i > 0 && nums[i] == nums[i-1]) {
      continue
    }
    l, r := i + 1, len(nums) - 1
    for l < r {
      n1, n2, n3 := nums[i], nums[l], nums[r]
      if n1 + n2 + n3 < 0 {
        l++
        continue
      }
      if n1 + n2 + n3 > 0 {
        r--
        continue
      }
      ret = append(ret, []int{n1, n2, n3})
      for l < r && nums[l] == n2 {
        l++
      }
      for l < r && nums[r] == n3 {
        r--
      }
    }
  }
  return ret
}

# 7. 四数之和(中等) (opens new window)

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abc 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

示例 1:

输入: nums = [1,0,-1,0,-2,2], target = 0
输出: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2:

输入: nums = [2,2,2,2,2], target = 8
输出: [[2,2,2,2]]

# JS

var fourSum = function (nums, target) {
  nums.sort((a, b) => a - b)
  let ret = []
  for (let i = 0; i < nums.length - 3; i++) {
    if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break
    if (i > 0 && nums[i] == nums[i - 1]) continue
    for (let j = i + 1; j < nums.length - 2; j++) {
      if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break
      if (j > i + 1 && nums[j] == nums[j - 1]) continue
      let l = j + 1, r = nums.length - 1
      while (l < r) {
        let n1 = nums[i], n2 = nums[j], n3 = nums[l], n4 = nums[r]
        if (n1 + n2 + n3 + n4 < target) {
          l++
          continue
        }
        if (n1 + n2 + n3 + n4 > target) {
          r--
          continue
        }
        ret.push([n1, n2, n3, n4])
        while (l < r && nums[l] == nums[++l]) continue
        while (l < r && nums[r] == nums[--r]) continue
      }
    }
  }
  return ret
}

# Golang

func fourSum(nums []int, target int) [][]int {
  sort.Ints(nums)
  var ret = [][]int{}

  for i := 0; i < len(nums) - 3; i++ {
    if (nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target) {
      break
    }
    if (i > 0 && nums[i] == nums[i - 1]) {
      continue
    }
    for j := i + 1; j < len(nums) - 2; j++ {
      if (nums[i] + nums[j] + nums[j+1] + nums[j+2] > target) {
        break
      }
      if (j > i + 1 && nums[j] == nums[j-1]) {
        continue
      }
      l, r := j + 1, len(nums) - 1
      for l < r {
        n1, n2, n3, n4 := nums[i], nums[j], nums[l], nums[r]
        if (n1 + n2 + n3 + n4 < target) {
          l++
          continue
        }
        if (n1 + n2 + n3 + n4 > target) {
          r--
          continue
        }
        ret = append(ret, []int{n1, n2, n3, n4})
        for l < r && nums[l] == n3 {
          l++
        }
        for l < r && nums[r] == n4 {
          r--
        }
      } 
    }
  }
  return ret
}
    爱自己,
    是终身浪漫的开始。
    红莲华
    x
    loading...