242.有效的字母异位词
题目:
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
思路:
分别设置两个map集合,对两个不同的字符串中的每个字符进行统计,map中key为字符值,value为字符出现的次数。
对两个map集合进行比较:先比较map集合的长度,对键的个数进行比较,如果不同返回false,再对两个集合中的键值进行精确比较,如果有不同,直接返回false,最后返回true。
代码:
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isAnagram = function(s, t) {
const stat = (s) => {
const obj = new Map()
for (let i = 0;i<s.length;i++) {
if (obj[s[i]]) {
obj[s[i]]++
}else {
obj[s[i]]=1
}
}
return obj
}
// console.log(stat(s))
const statS = stat(s)
const statT = stat(t)
const compare = (s,t) => {
if (Object.keys(s).length!==Object.keys(t).length) return false
for (let k in s) {
if (s[k]!==t[k]) {
return false
}
}
return true
}
return compare(statS,statT)
};
优化:
看了代码随想录的思路,自己重新写了一遍:设置一个数组,因为字符串中只包含小写字母,所以设置索引值为0-25,对第一个字符串中的每一个字符进行遍历,减去'a'的unicode编码,得到和索引对应的值,将数组中该索引对应值+1,对第二个字符串中的每一个字符进行遍历,按照上面的方法,对数组中该索引对应值-1,最后判断数组中的每个值是否等于0,如果不等于0直接返回false,最后返回true。 注意:在对数组进行遍历的过程中,利用forEach方法不可以用return返回,return只能跳出循环,也不能用every方法遍历途中return返回,因为every中只要执行到return就会直接返回。可以用for of方法,实现判断条件返回。
代码:
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isAnagram = function(s, t) {
const hash = new Array(26).fill(0)
for (let i = 0; i < s.length;i++) {
// console.log(s.charCodeAt(i))
hash[s.charCodeAt(i)-97]++
}
// console.log(hash)
for (let i = 0; i < t.length;i++) {
hash[t.charCodeAt(i)-97]--
}
// console.log(hash)
for (let el of hash) {
console.log(el)
if (el!==0) {
return false
}
}
return true
};
总结:
第一次接触哈希表,对基本概念都能理解,无论是数组还是set、map都是之前学到的东西,但是实际应用的时候会有点想当然,想不到最优的方法,也许会把问题弄的复杂。
349. 两个数组的交集
题目:
给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
思路:
?看到这题感觉好简单是我的错觉吗,对nums1使用filter方法,返回在nums2中存在的元素,最后使用扩展运算符搭配new Set直接输出结果
代码:
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var intersection = function(nums1, nums2) {
const arr = nums1.filter(el=>nums2.indexOf(el)!==-1)
console.log(...new Set(arr))
return [...new Set(arr)]
};
优化:
看了一下代码随想录的思路,是设置一个set集合,放入较长的数组,然后对较短的数组进行遍历,如果较长的数组中存在较短数组中的某个值,就放入一个新的set集合中,最后输入set转换后的数组。
代码:
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var intersection = function(nums1, nums2) {
if (nums1.length<nums2.length) {
const tmp = nums2
nums2 = nums1
nums1 = tmp
}
const numsSet = new Set(nums1)
const resSet = new Set()
for (let k of nums2) {
numsSet.has(k) && resSet.add(k)
}
return [...resSet]
};
总结:
耍一哈
const intersection = (nums1,nums2) => [...new Set(nums1.filter(el=>nums2.indexOf(el)!==-1))]
1. 两数之和
题目:
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果
n是 快乐数 就返回true;不是,则返回false。
思路:
首先得到一个数的每个位置上的数字平方和的结果,然后声明一个set集合,对这个结果进行判断,如果为1就返回true,如果不为1,先判断这个结果是否在set集合中,不在就把这个结果放进一个set集合中,然后对整个函数进行一次递归调用,如果在set集合中就返回false。
代码:
/**
* @param {number} n
* @return {boolean}
*/
var isHappy = function(n) {
const resSet = new Set()
const ishappy = (n) => {
const arr = []
while (n/10!==0) {
arr.push(parseInt(n%10))
n = parseInt(n/10)
}
// arr.push(n)
console.log(arr)
let res = arr.reduce((prev,cur)=>{
return prev+cur*cur
},0)
if (res===1){
return true
}else {
if (resSet.has(res)){
return false
}else {
resSet.add(res)
console.log(resSet)
return ishappy(res)
}
}
}
return ishappy(n)
};
优化:
自己的代码执行的时候用了很久,我就知道自己的代码肯定是比较笨的那一种,看了代码随想录的思路,感觉整体思路是一样的,但是他是用一个函数获取一个数的每个位置上的平方和,然后设置一个无限循环,内部对return的条件进行判断,如果都不生效,就重新获取当前的结果的每个位置上的平方和再次判断,时间复杂度更低。
代码:
var isHappy = function (n) {
const getRes = (n) => {
const arr = []
while (n / 10 !== 0) {
arr.push(parseInt(n % 10))
n = parseInt(n / 10)
}
// arr.push(n)
// console.log(arr)
let res = arr.reduce((prev, cur) => {
return prev + cur * cur
}, 0)
return res
}
let res = getRes(n)
const resSet = new Set()
while (true) {
if (res === 1) {
return true
}
if (resSet.has(res)) {
return false
}
resSet.add(res)
res = getRes(res)
}
};
总结:
这道题自己其实已经把大概思路想出来,加深了对哈希表的理解。
1. 两数之和
题目:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
思路:
只会暴力解法。
代码:
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function (nums, target) {
const arr = []
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] === target) {
arr.push(i)
arr.push(j)
}
}
}
return arr
};
优化:
看了代码随想录的思路,是先声明一个map集合,然后对数组进行一次遍历,取数组中每一个值与目标值的差值,在map集合中寻找这个差值,如果找到,就把当前值和差值的下标放入一个数组中返回,如果找不到,就把当前值和下标以键值对的形式存入map集合中。
代码:
var twoSum = function(nums, target) {
const twoMap = new Map()
let res = []
for (let i = 0;i<nums.length;i++) {
let diff = target - nums[i]
if (twoMap.has(diff)) {
res.push(i,twoMap.get(diff))
break
}else {
twoMap.set(nums[i],i)
}
}
// console.log([...twoMap.values()])
return res
};
总结:
希望自己能在不停做题的过程中更加熟练对哈希表的应用,比较难的其实是思路怎么想出来。
Day6总结
第一次写关于哈希表的题,有些生疏,但是能使用,一些题目大体思路是正确的,可能是逻辑不是最优的,感觉哈希表比链表简单一丢丢,毕竟数组setmap都是es6学过的知识。