242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和
今天手hash专场。
什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
当我们想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构:
数组
set (集合)
map(映射)
242.有效的字母异位词
leetcode-242.有效的字母异位词 ------简单
题目描述 && 测试案例
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
示例 1:
输入: s = “anagram”, t = “nagaram”
输出: true
示例 2:
输入: s = “rat”, t = “car”
输出: false
解题思路 && 解题代码
var isAnagram = function(s, t) {
//首先考虑不符合的情况,如果s和t的长度不相等。自然就不是异位词了。
if(s.length !== t.length) return false
//本道的核心就是看t的字母是不是在s中出现,也就是判断一个字符是否出现在s中,想到hash结构
//使用哪种结构?
//选择数组比较合适,26个字符长度固定为26,以0填充,出现了就在相应的位置+1,不涉及map的set等。
const arr1 = new Array(26).fill(0)
//遍历s字符串利用charcodeat得到码 在减去‘a’的,就得到了对应的0-25
for(let i = 0; i < s.length; i++) {
//遍历进行++
arr1[s[i].charCodeAt() - 'a'.charCodeAt()]++
}
//再次遍历t,进行--
for(let j = 0; j < t.length; j++) {
arr1[t[j].charCodeAt() - 'a'.charCodeAt()]--;
//如果减了之后变成负数就说明不相等,不相等的话就不是有效的,返回false
if(arr1[t[j].charCodeAt() - 'a'.charCodeAt()] < 0) {
return false
}
}
return true;
};
349.两个数组的交集
题目描述 && 测试案例
给定两个数组 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] 也是可通过的
解题思路 && 解题代码
集合论中,设A,B是两个集合,由所有属于集合A且属于集合B的元素所组成的集合,叫做集合A与集合B的交集(intersection),记作A∩B。
上一题使用了hash结构中的数组,但是如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。上一道题 hash值就是26个,所以使用数组是合适的,但这道题数组就不合适了,会造成浪费。
题目说每个结果是唯一的,三种结构中能做到唯一的就是set了,并且使用set进行去重,也降低了复杂度。
js中let…of与let…in
for in:(它大部分用于遍历数组的索引(key值))
定义:用于循环遍历数组或对象属性,fot in循环里面的index是string类型的,代码每执行一次,就会对数组的元素或者对象的属性进行一次操作
缺点:某些情况下,会出现随机顺序的遍历,因为里面的值是string类型,所以增加了转换过程,因此开销较大
优点:可以遍历数组的键名,遍历对象简洁方便
for of:(可遍历map,object,array,set string等)用来遍历数据,比如数组中的元素s值,
优点:避免了for in的所有缺点,可以使用break,continue和return,不仅支持数组的遍历,还可以遍历类似数组的对象,支持字符串的遍历
最简洁,最直接的遍历数组的语法,支持map和Set对象遍历
缺点:不适用于处理原有的原生对象(原生对象是一个子集,包含一些在运动过程中动态创建的对象)
var intersection = function(nums1, nums2) {
//使用set对两个数组先去重
let set1 = new Set(nums1)
let set2 = new Set(nums2)
let res = [];
for(let n1 of set1) {
if(set2.has(n1)){
res.push(n1)
}
}
return res
};
202. 快乐数
题目描述 && 测试案例
编写一个算法来判断一个数 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
解题思路 && 解题代码
var isHappy = function(n) {
//本道题的核心就是看有没有重复循环,有重复循环就false,重复的话就会想到set
let set = new Set();
//进行一个循环,什么时候循环?n!=1的时候,说明还不是快乐数
while(n != 1) {
//写一个得到下一个n的方法
n = getNext(n)
//如果下一个n在set里面肯定就返回false了
if(set.has(n)){
return false
}
set.add(n)
}
return n===1
};
//如何得到下一个n
var getNext = function(n) {
let sum = 0
while(n > 0){
sum = sum + Math.pow(n % 10, 2)
n = Math.floor(n / 10)
}
return sum
};
1. 两数之和
题目描述 && 测试案例
给定一个整数数组 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]
解题思路 && 解题代码
思路一:果然。。。。暴力大法好,不放代码了。
思路二:
var twoSum = function(nums, target) {
// 为什么会想到用哈希表?
//本道题的本质其实还是看一个元素target是否出现在一个数组里面
// 哈希表为什么用map
//数组的话,会造成浪费,set有去重功能,明显不太合适,所以选择map
// 本题map是用来存什么的
//map来存放我们遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是是否出现在这个集合。
// map中的key和value用来存什么的
//key存mums[i] value存对应是索引值。
//创建一个hash表
let hash = {};
//遍历数组nums
for(let i = 0; i < nums.length; i++) {
//如果targettarget- nums[i] !== undefined 就说明存在
if(hash[target - nums[i]] !== undefined) {
//returnreturn 下标
return [i, hash[target - nums[i]]];
}
//如果不存在,就添加到hash中
hash[nums[i]] = i;
}
//没有 返回空[]
return [];
};