242.有效的字母异位词
题目链接:242.有效的字母异位词
文档讲解:代码随想录/有效的字母异位词
视频讲解:视频讲解-有效的字母异位词
状态:已完成(1遍)
解题过程
看到题目的第一想法
我的第一想法和哈希没有半点关系,俗称笨办法,单词转换成字母数组,排个序,然后再转换成单词,看看一不一样就行了。
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isAnagram = function (s, t) {
if (s.length !== t.length) return false;
let sortS = s.split('').sort().join('');
let sortT = t.split('').sort().join('');
if (sortS == sortT) {
return true;
} else {
return false;
}
};
运行、提交都成功,那么看看代码随想录的哈希解法。
看完代码随想录之后的想法
这道题的文字讲解JS给了两版哈希解法,第一种是设一个长度为26的数组,来记录字符串各字母出现的次数,第二种是直接用Map键值对记录,个人还是比较习惯第二种。手搓一版问题不大。
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isAnagram = function (s, t) {
if(s.length !== t.length) return false;
let hashMap = {};
for(let i of s){
if(!hashMap[i]){
hashMap[i] = 1;
}else{
hashMap[i] +=1;
}
}
for(let i of t){
if(!hashMap[i]){
return false;
}else{
hashMap[i] -=1;
}
}
return true;
};
总结
这道题的笨办法代码看上去还是挺简便的,GPT一下优劣。
两种方法的时间复杂度在最坏情况下都是线性的,但在实际应用中可能会有差异。
就代码的简洁性和可读性而言,第二段代码使用了一个哈希表来计数字符出现的次数,代码逻辑相对清晰,容易理解。第一段代码则通过排序的方式来比较字符串是否相同,代码较为简洁。
综合考虑,如果字符串长度较小且不会存在大量重复字符,第一段代码使用排序的方式可能更简洁有效。但如果字符串长度较大或存在大量重复字符,第二段代码使用哈希表的方式可能更高效,因为它可以在一次遍历过程中完成计数。
349.两个数组的交集
题目链接:349.两个数组的交集
文档讲解:代码随想录/两个数组的交集
视频讲解:视频讲解-两个数组的交集
状态:已完成(1遍)
解题过程
看到题目的第一想法
想了想,感觉和上一道题有点相似,我继续在第一个数组中遍历,出现的数字当作键值对记录在哈希表中,然后在第二个数组中遍历,看看有没有对应的键,有的话记在输出数组中;
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var intersection = function(nums1, nums2) {
let hashMap = {};
let ans = [];
for(let i of nums1){
if(!hashMap[i]){//记录nums1中所有出现的数字,键:数字,值:1
hashMap[i] =1;
}
}
for(let j of nums2){
if(hashMap[j]==1){//如果nums2中的数字出现在hashMap的键中
ans.push(j);//答案推入一个此数字
hashMap[j] = 0;//给对应的值改成0,不然会重复推入答案
}
}
return ans;
};
看完代码随想录之后的想法
原来用Set可以自动实现去重,放进Set的就是唯一的。还学到了&&的短路特性。
讲解代码如下:
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var intersection = function(nums1, nums2) {
// 根据数组大小交换操作的数组
if(nums1.length < nums2.length) {
const _ = nums1;
nums1 = nums2;
nums2 = _;
}
const nums1Set = new Set(nums1);
const resSet = new Set();
// for(const n of nums2) {
// nums1Set.has(n) && resSet.add(n);
// }
// 循环 比 迭代器快
for(let i = nums2.length - 1; i >= 0; i--) {
nums1Set.has(nums2[i]) && resSet.add(nums2[i]);
}
return Array.from(resSet);
};
总结
使用数组来做哈希的题目,是因为题目都限制了数值的大小。
而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。
此时就要使用另一种结构体了,set 。
202.快乐数
题目链接:202.快乐数
文档讲解:代码随想录/快乐数
视频讲解:无
状态:已完成(1遍)
解题过程
看到题目的第一想法
如果这个数各个位数的数字平方和加起来不是1的话就一直加下去,如果是1就输出true,每次加完之后把这个数字记录进set里,要是set里已经有了,那说明肯定进入循环了,输出false。
/**
* @param {number} n
* @return {boolean}
*/
var isHappy = function(n) {
let allCount = n;//每次各个位数加起来的和
let set = new Set();
while(allCount!==1){
let allNums = allCount.toString().split('');
allCount = allNums.reduce((a,b)=>{
return a+b*b
},0);
if(set.has(allCount)) return false;
set.add(allCount);
}
return true;
};
运行提交都没问题,那么看看文字讲解。
看完代码随想录之后的想法
JS部分用了四种方法,综合来看感觉还是用reduce来求各个位数的数字平方和更简便一些,与解法四有些许差别,但我感觉直接将n赋值给allCount也没问题。
总结
这道题复习了哈希的Set用法。
1.两数之和
题目链接:1.两数之和
文档讲解:代码随想录/两数之和
视频讲解:视频讲解-两数之和
状态:已完成(1遍)
解题过程
看到题目的第一想法
双重for循环的想法按捺不住,先写一版看看。
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
for(let i = 0;i<nums.length-1;i++){
for(let j = i+1;j<nums.length;j++){
if((nums[i]+nums[j])==target) return [i,j];
}
}
};
看着真顺眼哈哈,不过还得学习哈希方法。
每遍历到nums中的一个数,算出另一个目标加数是多少,然后看看这个目标数是否在哈希表中存在,如果存在,那么输出结果,如果不存在,就把当前遍历的数存进哈希表。
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
let hashMap = {};
let targetNum;
for(let i = 0;i<nums.length;i++){
targetNum = target - nums[i];
if(!(hashMap[targetNum])){
hashMap[nums[i]] = i;
}else{
return [i,hashMap[targetNum]]
}
}
};
这下真小丑了,写完感觉没问题,但是就是不成功,debug了一下,发现,如果后面某个数的要找的另一个数是数组的第0个数,那么我的!0能让他也变成true。。。老老实实改成下面这版吧。
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
let hashMap = {};
let targetNum;
for(let i = 0;i<nums.length;i++){
targetNum = target - nums[i];
if(hashMap[targetNum]==undefined){
hashMap[nums[i]] = i;
}else{
return [i,hashMap[targetNum]]
}
}
};
这下没问题了。
看完代码随想录之后的想法
这道题目的思路跟我想的大概一致,就是上面那个bug太小丑了,各位看到了就别犯这种错误了哈哈。
总结
在此卡卡西一段文字讲解中关于哈希三种方法的对比。
因为本题,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。
再来看一下使用数组和set来做哈希法的局限。
- 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
- set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。
此时就要选择另一种数据结构:map ,map是一种key value的存储结构,可以用key保存数值,用value再保存数值所在的下标。