feat: 哈希表:1,49,128,202,205,219,242,290,383
This commit is contained in:
parent
0d078c09b4
commit
72ac2258de
58
top-interview-leetcode150/hash-table/128数组中连续序列的最长长度.js
Normal file
58
top-interview-leetcode150/hash-table/128数组中连续序列的最长长度.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/longest-consecutive-sequence/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {number[]} nums
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
const longestConsecutive = function (nums) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
思路:题目所给的数组是无序的,所以直接对数组排序,依次遍历整个数组,如果当前元素大于前一个元素,并且等于前一个元素加1,就
|
||||||
|
把统计的长度加1,如果不满足就比较是否比最大长度还大,是的话就把这个长度作为为最大长度
|
||||||
|
*/
|
||||||
|
|
||||||
|
function f1(nums) {
|
||||||
|
nums.sort((a, b) => a - b);
|
||||||
|
if (nums.length === 0) return 0;
|
||||||
|
if (nums.length === 1) return 1;
|
||||||
|
let maxLen = 1; // 最大长度
|
||||||
|
let curLen = 1; // 统计长度
|
||||||
|
for (let i = 1; i < nums.length; i++) {
|
||||||
|
const preNum = nums[i - 1];
|
||||||
|
if (nums[i] === preNum) {
|
||||||
|
continue;
|
||||||
|
} else if (preNum + 1 === nums[i]) {
|
||||||
|
curLen++;
|
||||||
|
} else {
|
||||||
|
maxLen = Math.max(maxLen, curLen);
|
||||||
|
curLen = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.max(curLen, maxLen); // 如果后面一个很长的连续序列
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
题目要求我们在O(n)的时间复杂度完成,上面的做法使用了一次排序,nlogn,不符合要求,正确的做法可以先用set对整个数组去重,
|
||||||
|
整个过程的时间复杂度为O(n),之后遍历整个Set,如果当前的num-1在set中不存在,就表明,这个num是数组中某个序列的开头,开始统计
|
||||||
|
num+1在set中存在吗?如果存在就计数加1,如果不存在继续遍历
|
||||||
|
*/
|
||||||
|
|
||||||
|
function f2(nums) {
|
||||||
|
if (nums.length === 0) return 0;
|
||||||
|
const set = new Set(nums);
|
||||||
|
let maxLen = 1;
|
||||||
|
let curLen = 1;
|
||||||
|
for (const num of set) {
|
||||||
|
if (set.has(num - 1)) continue;
|
||||||
|
// 表明num是某个连续序列的开头,直接开始统计
|
||||||
|
let next = num + 1;
|
||||||
|
while (set.has(next)) {
|
||||||
|
curLen++;
|
||||||
|
next++;
|
||||||
|
}
|
||||||
|
maxLen = Math.max(maxLen, curLen);
|
||||||
|
curLen = 1;
|
||||||
|
}
|
||||||
|
return maxLen;
|
||||||
|
}
|
21
top-interview-leetcode150/hash-table/1两数之和.js
Normal file
21
top-interview-leetcode150/hash-table/1两数之和.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
*https://leetcode.cn/problems/two-sum/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {number[]} nums
|
||||||
|
* @param {number} target
|
||||||
|
* @return {number[]}
|
||||||
|
*/
|
||||||
|
const twoSum = function (nums, target) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
创建一个map,map的key为target - num, value为下标,遍历nums,如果当前num在map中存在就返回[map.get(num), i],i表示当前
|
||||||
|
下标
|
||||||
|
*/
|
||||||
|
function f1(nums, target) {
|
||||||
|
const map = new Map();
|
||||||
|
for (let i = 0; i < nums.length; i++) {
|
||||||
|
if (map.has(nums[i])) return [map.get(nums[i]), i];
|
||||||
|
map.set(target - nums[i], i);
|
||||||
|
}
|
||||||
|
}
|
71
top-interview-leetcode150/hash-table/202快乐数.js
Normal file
71
top-interview-leetcode150/hash-table/202快乐数.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
*https://leetcode.cn/problems/happy-number/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {number} n
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const isHappy = function (n) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
根据快乐数的定义我们只需一直计数,把计数的结果放到Set中,如果在后续的计数中,出现了这个结果说明它不是快乐数(不能是1,所以要先
|
||||||
|
检测它是否是1,如果是的话就返回)
|
||||||
|
*/
|
||||||
|
function f1(n) {
|
||||||
|
// 使用set来记录出现过的数字
|
||||||
|
const seen = new Set();
|
||||||
|
|
||||||
|
// 循环直到满足条件
|
||||||
|
while (n !== 1) {
|
||||||
|
// 如果当前数字之前的某次计算出过,说明进入循环
|
||||||
|
if (seen.has(n)) return false;
|
||||||
|
|
||||||
|
// 将当前数字加入set
|
||||||
|
seen.add(n);
|
||||||
|
|
||||||
|
// 计算当前数字的每个位置的平方和
|
||||||
|
// n = n.toString().split('').reduce((sum, digit) => sum + Number(digit) ** 2, 0);
|
||||||
|
// 优化:通过取余和除法运算计算每一位的平方和
|
||||||
|
let sum = 0;
|
||||||
|
while (n > 0) {
|
||||||
|
const digit = n % 10;
|
||||||
|
sum += digit * digit;
|
||||||
|
n = Math.floor(n / 10);
|
||||||
|
}
|
||||||
|
n = sum;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
利用弗洛伊德环形检测算法
|
||||||
|
*/
|
||||||
|
function f2(n) {
|
||||||
|
let slow = n; // 慢指针
|
||||||
|
let fast = n; // 快指针
|
||||||
|
|
||||||
|
// 快慢指针循环
|
||||||
|
while (fast !== 1 && getSumOfSquares(fast) !== 1) { // getSumOfSquares(fast) !== 1直接提前判定慢指针
|
||||||
|
slow = getSumOfSquares(slow);
|
||||||
|
fast = getSumOfSquares(getSumOfSquares(fast));
|
||||||
|
if (slow === fast) { // 如果快慢指针相遇,说明出现了循环
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number} num 要计算各位平方和的数
|
||||||
|
* @returns 返回计算平方和的数
|
||||||
|
*/
|
||||||
|
function getSumOfSquares(num) {
|
||||||
|
let sum = 0;
|
||||||
|
while (num > 0) {
|
||||||
|
const digit = num % 10;
|
||||||
|
sum += digit * digit;
|
||||||
|
num = Math.floor(num / 10);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
60
top-interview-leetcode150/hash-table/205同构字符串.js
Normal file
60
top-interview-leetcode150/hash-table/205同构字符串.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/isomorphic-strings/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {string} s
|
||||||
|
* @param {string} t
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const isIsomorphic = function (s, t) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
s和t的长度是一致的,s中的字符会按照某种关系映射到t,比如: a->b, b->c,但是不会出现a->c, b->c这种多个字符映射同一个字符,如果出现
|
||||||
|
这种情况直接返回false,也不会出现a->b, a->c这种一个字符有多个映射的情况,如果有直接返回false。
|
||||||
|
思路: 同时遍历s和t,s[i]作为hashTable的key,t[i]作为hashTable的值,如果s[i] 在hashTable中存在,检查其对应的value是否和
|
||||||
|
t[i]一致,如果不一致,就出现了 a-b, a->c这种一个字符出现多映射的情况,直接返回false,最后遍历一遍hashtable,检查是否存在,多个
|
||||||
|
value相同的情况,如果出现则表明出现了,a-c,b->c这种多个字符映射到同一个字符的情况
|
||||||
|
*/
|
||||||
|
function f1(s, t) {
|
||||||
|
const map = new Map();
|
||||||
|
|
||||||
|
for (let i = 0; i < s.length; i++) {
|
||||||
|
if (map.has(s[i])) {
|
||||||
|
if (map.get(s[i]) !== t[i]) return false;
|
||||||
|
} else {
|
||||||
|
map.set(s[i], t[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 利用set查看map的value是否有重复
|
||||||
|
const set = new Set();
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
for (const [_, value] of map) {
|
||||||
|
if (set.has(value)) return false;
|
||||||
|
set.add(value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
我们在处理a->b,a->c这种多映射的情况非常好处理,一次遍历就行,但是在遇到a->c,b->c这种被多个字符映射的情况需要遍历
|
||||||
|
一遍map的所有value,这无疑增加了复杂度,所以可以再增加一个set用来储存哪些字符应该被映射过了,如果出现了一个没有映射
|
||||||
|
的字符,但是它要映射的那个字符在set中已经存在,直接返回false,英文出现了多个字符映射到同一个字符的情况
|
||||||
|
*/
|
||||||
|
function f2(s, t) {
|
||||||
|
// 创建两个map,一个储存字符的映射,一个储存哪些字符已经被映射过了
|
||||||
|
const charMap = new Map();
|
||||||
|
const hasBeenMap = new Set();
|
||||||
|
for (let i = 0; i < s.length; i++) {
|
||||||
|
if (charMap.has(s[i])) {
|
||||||
|
if (charMap.get(s[i]) !== t[i]) return false;
|
||||||
|
} else {
|
||||||
|
// 检查t[i]是否已经被映射
|
||||||
|
if (hasBeenMap.has(t[i])) return false;
|
||||||
|
charMap.set(s[i], t[i]); // 将映射关系加入 charMap
|
||||||
|
hasBeenMap.add(t[i]); // 将 t[i] 标记为已映射
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
67
top-interview-leetcode150/hash-table/219存在重复元素.js
Normal file
67
top-interview-leetcode150/hash-table/219存在重复元素.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/contains-duplicate-ii/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {number[]} nums
|
||||||
|
* @param {number} k
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const containsNearbyDuplicate = function (nums, k) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
定义两个指针表示abs(i - j) <= k的窗口,i向右移动,查看当前指向的值在set中是否存在,不存在就把这个值存入set,如果i-j >k 表明
|
||||||
|
当前太大了,要缩小,把j指向的元素从set中剔除掉,i++,并将测j指向的值是否在set中存在
|
||||||
|
*/
|
||||||
|
function f1(nums, k) {
|
||||||
|
const set = new Set();
|
||||||
|
|
||||||
|
for (let i = 0, j = 0; i < nums.length; i++) {
|
||||||
|
// 如果 窗口太大,就缩小窗口再检测
|
||||||
|
if (i - j > k) {
|
||||||
|
set.delete(nums[j]);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测 nums[i]是否在set中存在
|
||||||
|
if (set.has(nums[i])) return true;
|
||||||
|
|
||||||
|
// 将当前值存入set
|
||||||
|
set.add(nums[j]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
优化,上面代码中i-j<k的检测是多余的,因为,当i>k时i-j一定大于k,因为后续我们会一个值一个值的检测,例如:当k=3,i=4时,这个时候
|
||||||
|
一定要缩小串口,直接剔除掉i-k-1表示的元素即可,set中剩下的元素还是4个,这样可以少用一个下标,判断也更快
|
||||||
|
*/
|
||||||
|
function f2(nums, k) {
|
||||||
|
const set = new Set();
|
||||||
|
|
||||||
|
for (let i = 0; i < nums.length; i++) {
|
||||||
|
// 超出滑动窗口
|
||||||
|
if (i > k) {
|
||||||
|
set.delete(nums[i - k - 1]);
|
||||||
|
}
|
||||||
|
// 检测set中是否含有这个元素
|
||||||
|
if (set.has(nums[i])) return true;
|
||||||
|
set.add(nums[i]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
直接一次遍历,利用map储存之前遍历的所有值和下标,如果当前值在map中存在,并且当前值的下标减去map中对应值的小标,结果小于等于k
|
||||||
|
则表明发生了重复
|
||||||
|
*/
|
||||||
|
|
||||||
|
function f3(nums, k) {
|
||||||
|
const map = new Map();
|
||||||
|
|
||||||
|
for (let i = 0; i < nums.length; i++) {
|
||||||
|
const num = nums[i];
|
||||||
|
if (map.has(num) && i - map.get(num) <= k) return true;
|
||||||
|
map.set(num, i);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
51
top-interview-leetcode150/hash-table/242有效的字母异位词.js
Normal file
51
top-interview-leetcode150/hash-table/242有效的字母异位词.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/valid-anagram/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {string} s
|
||||||
|
* @param {string} t
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const isAnagram = function (s, t) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
判断s是否是t的异位词,异位词就是重新排列字符顺序的词就是异位词,所以异位词的长度和原本单词的长度一致,同一个字符出现的次数也一致
|
||||||
|
题目的输入只包含26个小写字母,所利用数组的下标表示t中出现的小写字母,值为出现的次数,之后遍历s,s中的每个单词会使其对应的计数减少
|
||||||
|
1,如果出现某个计数小于0直接返回false
|
||||||
|
*/
|
||||||
|
function f1(s, t) {
|
||||||
|
if (s.length !== t.length) return false;
|
||||||
|
// 统计t中字母出现的频次
|
||||||
|
const charCounts = new Array(26).fill(0);
|
||||||
|
for (let i = 0; i < t.length; i++) {
|
||||||
|
charCounts[t.charCodeAt(i) - 97]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < s.length; i++) {
|
||||||
|
const index = s.charCodeAt(i) - 97;
|
||||||
|
charCounts[index]--;
|
||||||
|
if (charCounts[index] < 0) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
处理unicode字符,js中有一个坑,使用t[i]取unicode字符时,如果这个字符是一个代理对,比如emjoy表情,就会使用两个unicode16表示
|
||||||
|
所以应该使用for of来处理,应该字符串本身就是一个可迭代对象,底层会保证它返回的字符是正确的
|
||||||
|
*/
|
||||||
|
function f2(s, t) {
|
||||||
|
if (s.length !== t.length) return false;
|
||||||
|
|
||||||
|
const map = new Map();
|
||||||
|
for (const ch of t) {
|
||||||
|
map.set(ch, (map.get(ch) || 0) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ch of s) {
|
||||||
|
if (!map.has(ch)) return false;
|
||||||
|
map.set(ch, map.get(ch) - 1);
|
||||||
|
if (map.get(ch) < 0) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
40
top-interview-leetcode150/hash-table/290单词规律.js
Normal file
40
top-interview-leetcode150/hash-table/290单词规律.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
*https://leetcode.cn/problems/word-pattern/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {string} pattern
|
||||||
|
* @param {string} s
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const wordPattern = function (pattern, s) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
和205类似,只不过pattern中的字符映射到s中是一个单词,首先处理s,把s中每一个单词分离出来用数组储存,之后遍历pattern和这个数组,如果这个
|
||||||
|
map中存在这个key,就查看当前key对应的值是否和数组的值相等,如果不相等就返回false, 如果出现多个字符映射同一个字符也返回false,和205一致,
|
||||||
|
这里不过多解释
|
||||||
|
*/
|
||||||
|
function f1(pattern, s) {
|
||||||
|
const map = new Map();
|
||||||
|
const words = s.split(' ');
|
||||||
|
if (pattern.length !== s.length) return false;
|
||||||
|
for (let i = 0; i < pattern.length; i++) {
|
||||||
|
if (map.has(pattern[i])) {
|
||||||
|
if (map.get(pattern[i]) !== words[i]) return false;
|
||||||
|
} else {
|
||||||
|
map.set(pattern[i], words[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测是否出现了多个字符映射同一个字符串
|
||||||
|
const set = new Set();
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
for (const [_, value] of map) {
|
||||||
|
if (set.has(value)) return false;
|
||||||
|
set.add(value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
参考205,优化思路一致,可以使用数组储存对应映射,查找更快,使用set保存已经被映射过的单词,去除最后一次遍历
|
||||||
|
*/
|
68
top-interview-leetcode150/hash-table/383赎金信.js
Normal file
68
top-interview-leetcode150/hash-table/383赎金信.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/ransom-note/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {string} ransomNote
|
||||||
|
* @param {string} magazine
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const canConstruct = function (ransomNote, magazine) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
思路:用hash表统计magazine中的字符出现的数量,之后遍历ransomNote,如果ransomNote中有字符不在这个hash表中,说明magazine不能
|
||||||
|
构成ransomNote,如果这个字符在magazine中存在,就使其计数减1,如果计数为零就从哈希表中删除这个字符
|
||||||
|
*/
|
||||||
|
function f1(ransomNote, magazine) {
|
||||||
|
const map = new Map(); // 利用hash计数
|
||||||
|
for (let i = 0; i < magazine.length; i++) {
|
||||||
|
map.set(magazine[i], (map.get(magazine[i]) || 0) + 1); // 如果map中有这个字符就在原有的基础上加1,没有就设置成1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历ransomNote中的字符,如果字符在map中不存在就返回false
|
||||||
|
|
||||||
|
for (let i = 0; i < ransomNote.length; i++) {
|
||||||
|
const char = ransomNote[i];
|
||||||
|
if (map.has(char)) {
|
||||||
|
map.set(char, map.get(char) - 1);
|
||||||
|
// 如果发现当前字符计数为零,从map中删除这个字符
|
||||||
|
if (map.get(char) === 0) {
|
||||||
|
map.delete(char);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
使用数组来代替hash表,因为题目所给的测试用例只有26个小写的英文字符,可以使用一个长度为26的数组,数组的第一个位置代表a,最后一个位置代表
|
||||||
|
z,每个位置的值代表这个字符在magazine中出现的位置。
|
||||||
|
思考:为什么使用数组会更快,虽然hash查找操作时间复杂度理论上式O(1),但是hash计数,到对应的链表查找数据还是需要花费时间的,在数据量
|
||||||
|
大的时候可以认为是O(1),但是我们只需统计26个英文字符的数量,直接使用数组,数组在内存中是连续的,通过偏移量查找,非常快
|
||||||
|
*/
|
||||||
|
function f2(ransomNote, magazine) {
|
||||||
|
const charsCount = new Array(26).fill(0); // 统计magazine中每一个字符出现的次数
|
||||||
|
|
||||||
|
// 统计magazine中的字符
|
||||||
|
for (let i = 0; i < magazine.length; i++) {
|
||||||
|
const index = magazine.charCodeAt(i) - 97;
|
||||||
|
charsCount[index]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历ransomNote中的字符在charscount中是否存在
|
||||||
|
|
||||||
|
for (let i = 0; i < ransomNote.length; i++) {
|
||||||
|
const index = ransomNote.charCodeAt(i) - 97;
|
||||||
|
|
||||||
|
// if (charsCount[index] > 0) {
|
||||||
|
// charsCount[index]--;
|
||||||
|
// } else {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
if (charsCount[index] === 0) return false;
|
||||||
|
charsCount[index]--;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
103
top-interview-leetcode150/hash-table/49字母异位词分组.js
Normal file
103
top-interview-leetcode150/hash-table/49字母异位词分组.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* https://leetcode.cn/problems/group-anagrams/?envType=study-plan-v2&envId=top-interview-150
|
||||||
|
* @param {string[]} strs
|
||||||
|
* @return {string[][]}
|
||||||
|
*/
|
||||||
|
const groupAnagrams = function (strs) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
题目要求我们对字符串中的异位词分组,首先创建一个map,遍历strs中的所有字符串,查看它是否是map中某一个key的异位词,如果是的话,就
|
||||||
|
把它插入到这个key对应的数组中去,如果不是的话,表明他是一个新的字符串,所以在map中创建一个映射,用来收集它的异位词
|
||||||
|
*/
|
||||||
|
function f1(strs) {
|
||||||
|
const map = new Map();
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < strs.length; i++) {
|
||||||
|
let found = false;
|
||||||
|
|
||||||
|
// 查找 map 中是否有对应的异位词
|
||||||
|
for (const [key, value] of map) {
|
||||||
|
if (key.length === strs[i].length && isAnagram(strs[i], key)) {
|
||||||
|
value.push(strs[i]); // 如果是异位词,加入现有的数组
|
||||||
|
found = true; // 标记找到
|
||||||
|
break; // 找到就停止遍历
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有找到,就创建新的异位词组
|
||||||
|
if (!found) {
|
||||||
|
map.set(strs[i], [strs[i]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 map 中的所有异位词数组收集到 result
|
||||||
|
for (const [, value] of map) {
|
||||||
|
result.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
利用字符序来判断异位词
|
||||||
|
*/
|
||||||
|
function f2(strs) {
|
||||||
|
const map = new Map();
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
// 遍历所有字符串
|
||||||
|
for (let i = 0; i < strs.length; i++) {
|
||||||
|
// 排序字符串,得到标准化形式
|
||||||
|
const sortedStr = strs[i].split('').sort().join('');
|
||||||
|
|
||||||
|
// 如果 map 中已经有这个排序后的字符串,就将当前字符串加入对应的数组
|
||||||
|
if (map.has(sortedStr)) {
|
||||||
|
map.get(sortedStr).push(strs[i]);
|
||||||
|
} else {
|
||||||
|
// 如果没有,创建新的映射
|
||||||
|
map.set(sortedStr, [strs[i]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 map 中的所有异位词数组收集到 result
|
||||||
|
for (const [, value] of map) {
|
||||||
|
result.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测两个词是否是异位词
|
||||||
|
function isAnagram(s, t) {
|
||||||
|
if (s.length !== t.length) return false;
|
||||||
|
const charCounts = new Array(26).fill(0);
|
||||||
|
|
||||||
|
for (let i = 0; i < s.length; i++) {
|
||||||
|
charCounts[s.charCodeAt(i) - 97]++;
|
||||||
|
charCounts[t.charCodeAt(i) - 97]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return charCounts.every((count) => count === 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
利用一个数组来储存str的字符计数,如果计数相同就判断它们是异位词,这个代码巧妙之处是直接把数组作为key,本质就是调用数组的toString()
|
||||||
|
之后拿这个string作为对象的key,map中不能直接使用,因为map是通过引用来判断的,即使内容一样,也会判为,不同的str,如果非要要用map,可以
|
||||||
|
使用 String(count)作为map的key
|
||||||
|
*/
|
||||||
|
function f3(strs) {
|
||||||
|
// eslint-disable-next-line no-new-object
|
||||||
|
const map = new Object();
|
||||||
|
for (const s of strs) {
|
||||||
|
const count = new Array(26).fill(0);
|
||||||
|
for (const c of s) {
|
||||||
|
count[c.charCodeAt() - 'a'.charCodeAt()]++;
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
map[count] ? map[count].push(s) : map[count] = [s];
|
||||||
|
}
|
||||||
|
return Object.values(map);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user