判断
ransomNote能否由magazine的字符构成(每个字符只能用一次),字符仅限小写字母。
var canConstruct = function(ransomNote, magazine) {
// 如果赎金信更长,肯定不行
if (ransomNote.length > magazine.length) return false;
// 桶计数:26 个小写字母
const count = new Array(26).fill(0);
// a -> 0, b -> 1, ..., z -> 25
const aCode = 'a'.charCodeAt(0);
// 统计杂志中每个字符出现次数
for (const c of magazine) count[c.charCodeAt(0) - aCode]++;
// 遍历赎金信,消耗字符
for (const c of ransomNote) {
const idx = c.charCodeAt(0) - aCode;
if (count[idx] === 0) return false; // 字符不够用
count[idx]--;
}
return true;
};判断两个字符串是否同构:相同位置的字符存在一一映射关系,且不同字符不能映射到同一字符。
var isIsomorphic = function(s, t) {
if (s.length !== t.length) return false;
const lastS = {}, lastT = {};
// 记录每个字符上一次出现的位置(i+1 避免 0 与 undefined 混淆)
for (let i = 0; i < s.length; i++) {
if (lastS[s[i]] !== lastT[t[i]]) return false;
lastS[s[i]] = i + 1;
lastT[t[i]] = i + 1;
}
return true;
};var wordPattern = function(pattern, s) {
const words = s.split(' ');
if (pattern.length !== words.length) return false;
// 用 Map 避免原型链属性干扰(如 "constructor")
const mapP = new Map(), mapW = new Map();
for (let i = 0; i < pattern.length; i++) {
// 记录每个字符/单词的首次出现位置
if (!mapP.has(pattern[i])) mapP.set(pattern[i], i);
if (!mapW.has(words[i])) mapW.set(words[i], i);
// 比较首次出现位置是否一致
if (mapP.get(pattern[i]) !== mapW.get(words[i])) return false;
}
return true;
};判断两个字符串是否由相同字符以相同数量组成(仅含小写字母)。
var isAnagram = function(s, t) {
if (s.length !== t.length) return false;
// 一个桶:s 加、t 减,最终应全部归零
const count = new Array(26).fill(0);
for (let i = 0; i < s.length; i++) {
count[s.charCodeAt(i) - 97]++;
count[t.charCodeAt(i) - 97]--;
}
// 检查是否全零
for (const c of count) {
if (c !== 0) return false;
}
return true;
};将字符组成相同的字符串归为一组(仅含小写字母)。
var groupAnagrams = function(strs) {
const map = new Map();
for (const str of strs) {
// 统计每个字母出现次数
const count = new Array(26).fill(0);
for (let i = 0; i < str.length; i++) {
count[str.charCodeAt(i) - 97]++;
}
// 用字符编码压缩成 26 位 key,比 join(',') 更短更快
const key = String.fromCharCode(...count);
if (map.has(key)) {
map.get(key).push(str);
} else {
map.set(key, [str]);
}
}
return Array.from(map.values());
};找到两个数之和等于 target 的下标,每个输入只有唯一解。
var twoSum = function(nums, target) {
// 存储已遍历的值 -> 下标
const prev = new Map();
for (let i = 0; i < nums.length; i++) {
const complement = target - nums[i];
// 前面出现过 complement,配对成功
const j = prev.get(complement);
if (j !== undefined) return [j, i];
prev.set(nums[i], i);
}
};反复求各位平方和,判断最终能否收敛到 1,而非进入循环。
var isHappy = function(n) {
const sumSquares = (x) => {
let sum = 0;
while (x) {
const d = x % 10;
sum += d * d;
x = Math.floor(x / 10);
}
return sum;
};
const seen = new Set();
while (n !== 1) {
if (seen.has(n)) return false; // 进入循环
seen.add(n);
n = sumSquares(n);
}
return true;
};判断是否存在距离 ≤ k 的相同元素。
var containsNearbyDuplicate = function(nums, k) {
const lastIdx = new Map();
for (let i = 0; i < nums.length; i++) {
const j = lastIdx.get(nums[i]);
if (j !== undefined && i - j <= k) return true;
lastIdx.set(nums[i], i);
}
return false;
};在 O(n) 时间内找出未排序数组中最长连续序列的长度。
var longestConsecutive = function(nums) {
if (!nums.length) return 0;
const set = new Set(nums);
let maxLen = 0;
for (const num of set) {
// 只从连续序列的最小值开始统计
if (set.has(num - 1)) continue;
let cur = num;
while (set.has(cur + 1)) cur++;
maxLen = Math.max(maxLen, cur - num + 1);
}
return maxLen;
};