skip to content
1874

算法训练营第5天|242.有效的字母异位词、349.两个数组的交集、202.快乐数、1.两数之和

/ 9 min read

最后更新:
  1. 今日学习的文章链接和视频链接
  2. 自己看到题目的第一想法
  3. 看完代码随想录之后的想法
  4. 自己实现过程中遇到哪些困难
  5. 今日收获,记录一下自己的学习时长

题目链接

哈希表理论基础

建议:大家要了解哈希表的内部实现原理,哈希函数,哈希碰撞,以及常见哈希表的区别,数组,set 和map。

什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。 这句话很重要,大家在做哈希表题目都要思考这句话。

文章讲解:https://programmercarl.com/哈希表理论基础.html

242.有效的字母异位词

建议: 这道题目,大家可以感受到 数组 用来做哈希表 给我们带来的遍历之处。

题目链接/文章讲解/视频讲解:https://programmercarl.com/0242.有效的字母异位词.html

349.两个数组的交集

建议:本题就开始考虑 什么时候用set 什么时候用数组,本题其实是使用set的好题,但是后来力扣改了题目描述和 测试用例,添加了 0 <= nums1[i], nums2[i] <= 1000 条件,所以使用数组也可以了,不过建议大家忽略这个条件。 尝试去使用Set

题目链接/文章讲解/视频讲解:https://programmercarl.com/0349.两个数组的交集.html

202.快乐数

建议:这道题目也是 Set 的应用,其实和上一题差不多,就是 套在快乐数一个壳子

题目链接/文章讲解:https://programmercarl.com/0202.快乐数.html

1.两数之和

建议:本题虽然是 力扣第一题,但是还是挺难的,也是 代码随想录中 数组,set之后,使用map解决哈希问题的第一题。

建议大家先看视频讲解,然后尝试自己写代码,在看文章讲解,加深印象。

题目链接/文章讲解/视频讲解:https://programmercarl.com/0001.两数之和.html

解题思路

242.有效的字母异位词

关键词

  1. 有限的字符,判断重复性问题,就用 hash 表来解决

思路

  • 当两个字符长度不同,直接返回 false
  • 收集第一个字符s出现的次数,当遍历第二个字符 t的时候,如果出现次数为 0 的情况就说明t比 s 多了某个字符,直接返回 false,而不用再收集了。只有遍历下来,s 中所有的字符都出现在了 t 中,就不会再循环中出现字符数量为 0 的情况

349.两个数组的交集

关键词

  1. Set 的构造方法和 Set 转 Array

思路

  • 不需要记录数字出现的次数,所以不需要用 map,直接用两个 Set即可

  • nums1 转换为 Set 1,然后遍历 nums2,将在Set1 中出现过的相同的数字存放在一个新的 Set2 中,最后返回新的 Set2

  • 思路图

    image.png

202.快乐数

关键词

  1. 拆分数字
  2. 善用 reduce 累加器
  3. 用 set 存放 totalCount

思路

  • 只要totalCount不为 1,就一直循环
  • 用 set 存放 totalCount,如果totalCount出现过 1 次以上,说明进入了无限循环,直接返回 false

1.两数之和

关键词

  1. 用差值来寻找元素
  2. Map 存放元素和其下标

思路

  • 用Map 存放元素和其下标,用给定的目标值和当前元素做差值,在 Map 中寻找差值即可
  • 如果找到了就返回当前元素的下标和 Map 中差值元素的下标
  • 能判断当前值比目标元素大就跳过,因为可能存在负数

题解

242.有效的字母异位词

var isAnagram = function(s, t) {
// 如果两个字符长度不相等,直接返回 false
if(s.length !== t.length) return false;
// 用 hash map来存储 字符和字符出现的次数
const map = new Map()
for (let i = 0; i < s.length; i++) {
const char = s[i]
const ex = map.get(char)
if (ex) {
map.set(char, ex + 1)
} else {
map.set(char, 1)
}
}
for (let i = 0; i < t.length; i++) {
const char = t[i]
const ex = map.get(char)
if (ex) {
// 如果 t 字符也出现了已有的字符,直接--次数
map.set(char, ex -1 )
} else {
// 一旦 t 字符中出现了小于等于 0 的字符,说明 t 字符数量比 s 字符多了,直接返回 false
return false
}
}
// 如果字母出现的次数都相等,就返回 true
return true
};

349.两个数组的交集

var intersection = function(nums1, nums2) {
// 可以直接使用 Set 的构造方法,将数组变成 Set
const set1 = new Set(nums1)
const set2 = new Set()
for (let i = 0; i < nums2.length; i++) {
set1.has(nums2[i]) && set2.add(nums2[i])
}
// 可以直接使用 Array.from 将 Set 转为 Array
return Array.from(set2)
};

202.快乐数

var isHappy = function(n) {
// 记录累加数,最后要拿这个判断时候是 等于 1
let totalCount = 0
const set = new Set()
// 当totalCount不为 1 时循环继续
while (totalCount !== 1) {
// 对数字进行拆分为单个数字,第一次运行时应该使用传入的 n 作为其实数字
arr = String(totalCount || n).split('')
for (let i = 0; i < arr.length; i++) {
// totalCount += arr[i] * arr[i]
// 这里使用reduce累加器更简单。reduce第二个参数为初始值 0
// pre 就是上一次计算的值,也就是 total, cur 就是这一次的值
totalCount = arr.reduce((pre, cur) => {
return pre + cur * cur
}, 0)
}
// 这里要防止某些数字即使拆分和累加之后一直是无限循环下去的,可以使用 Set 进行去重
// 如果totalCount出现过一次以上,说明这个数即使拆分下去还是会出现相同的结果,会变成无限循环,那就直接判断为 false
if (set.has(totalCount)) {
return false
}
// 否则用 Set 记录下totalCount的值
set.add(totalCount)
}
// 如果循环完就意味着没有出现重复的,结果一定是 1
// 原本写的是 return totalCount === 1,但后面想了下如果totalCount不为 1,while 循环会一直持续下去,不可能走到这里
return true
};

1.两数之和

var twoSum = function(nums, target) {
// map 中存放 key 为元素,value 为元素的 index
const map = new Map()
for (let i = 0; i < nums.length; i++) {
const cur = nums[i]
// 这里不能判断比目标元素大就跳过,因为可能存在负数
// if (cur > target) continue
const gap = target - cur
// 从 map 中找差值
const v = map.get(gap)
if (v !== undefined) {
// 找到差值就直接返回对应两个元素的下标
return [v, i]
}
// 没找到就 set 当前元素和下标
map.set(cur, i)
}
};

收获

  • 当遇到要快速判断某个元素是否出现在集合中的时候,就要考虑哈希法