🧠 小哆啦解题记——谁偷调了我的字母顺序?

📅 2025-07-08|Day 34

题号:242. 有效的字母异位词 - 力扣(LeetCode)


第一章:静香的诗,胖虎也能写?

"你看!"静香一边甩着 ponytail,一边递过来两张纸:

ini 复制代码
s = "anagram"
t = "nagaram"

"你敢信?胖虎说他是'原创'诗人,他写的 t 明明是把我 s 字母顺序调了个顺序!"

大雄挠头:"那也不能直接说是抄袭吧?字母顺序不一样,怎么说是'一样'的呢?"

哆啦A梦一口咬掉半个铜锣烧:"这就叫------字母异位词(Anagram) 。"


第二章:异位词到底是什么鬼?

"字母异位词"指的是:

✅ 两个字符串长度相等

✅ 每个字符出现的次数完全相同

✅ 顺序可以不同(谁先谁后无所谓)

哆啦A梦递给大雄一块"排序魔方":"你可以先试试排序法,简单粗暴。"


第三章:排序法 · 快速检测器上线!

csharp 复制代码
function isAnagram(s: string, t: string): boolean {
    if (s.length !== t.length ) return false;

    let sArr: string[] = s.split('').sort();
    let tArr: string[] = t.split('').sort();

    return sArr.join('') === tArr.join('');
}

🧠 思路:排序后相等,就说明字母组成一模一样。

⏱ 时间复杂度:O(n log n);优点是写法清晰,缺点是排序浪费时间。

静香:

"不错,但如果我写了一首十万字的长诗,你还用 .sort(),电脑得原地升天。"


第四章:双 Map 频次追踪术 · 我自己数!

哆啦A梦:

"那就靠你自己数数每个字母出现了几次!"

于是大雄写出双 Map 频率比较器(正是你写的那一版):

vbnet 复制代码
function isAnagram(s: string, t: string): boolean {
    if (s.length !== t.length) return false;

    let sArr: string[] = s.split("");
    let tArr: string[] = t.split("");
    let sMap: Map<string, number> = new Map();
    let tMap: Map<string, number> = new Map();

    for (let i = 0; i < s.length; i++) {
        // 更新 sMap
        if (sMap.has(sArr[i])) {
            let num = sMap.get(sArr[i])!;
            sMap.set(sArr[i], num + 1);
        } else {
            sMap.set(sArr[i], 1);
        }

        // 更新 tMap
        if (tMap.has(tArr[i])) {
            let num = tMap.get(tArr[i])!;
            tMap.set(tArr[i], num + 1);
        } else {
            tMap.set(tArr[i], 1);
        }
    }

    // 合并 key,防止某个 map 缺 key
    let aSet: string[] = Array.from(new Set([...sMap.keys(), ...tMap.keys()]));

    for (let i = 0; i < aSet.length; i++) {
        if (tMap.get(aSet[i]) !== sMap.get(aSet[i])) return false;
    }

    return true;
}

哆啦A梦点头:"你这次写得很好!不过可以再简洁点。"


第五章:简化!优化!干净利落!

大雄瞪大眼:"能更短?"

哆啦A梦:"当然!你完全可以把两个 Map 合成一个!"

✅ 优化版:一个 Map 解决战斗(频次差值法)

vbnet 复制代码
function isAnagram(s: string, t: string): boolean {
    if (s.length !== t.length) return false;

    let map: Map<string, number> = new Map();

    for (let i = 0; i < s.length; i++) {
        map.set(s[i], (map.get(s[i]) || 0) + 1);
        map.set(t[i], (map.get(t[i]) || 0) - 1);
    }

    for (let val of map.values()) {
        if (val !== 0) return false;
    }

    return true;
}

🧠 思路:一个 Map 同时统计 s 的字符 +1,t 的字符 -1,如果最后每个字母都为 0,说明字符频次相等!


第六章:终极版本(全 ASCII 字符)提升性能!

如果你知道字符串只包含小写字母(a-z),还可以用数组代替 Map,加速:

ini 复制代码
function isAnagram(s: string, t: string): boolean {
    if (s.length !== t.length) return false;

    const freq: number[] = new Array(26).fill(0);
    const aCode = 'a'.charCodeAt(0);

    for (let i = 0; i < s.length; i++) {
        freq[s.charCodeAt(i) - aCode]++;
        freq[t.charCodeAt(i) - aCode]--;
    }

    return freq.every(count => count === 0);
}

🧪 测试一下吧!

ruby 复制代码
isAnagram("anagram", "nagaram"); // ✅ true
isAnagram("rat", "car");         // ❌ false
isAnagram("aacc", "ccac");       // ❌ false
isAnagram("", "");               // ✅ true

📌 技术启示录:

解法 优点 缺点 复杂度
排序法 简洁易写 时间略慢 O(n log n) 时间+空间
双 Map 通用、适合全字符集 写法稍冗 O(n)
差值 Map 优化 简洁高效,双向处理 要理解减法逻辑 O(n)
频次数组法 最快,空间固定 O(1) 仅适用于小写字母 O(n)

🌌 终章:字符重组的算法之美

大雄仰望窗外星空:

"原来一个词和另一个词之间的关系,

并不在乎顺序,

而是------他们有没有一样的'灵魂'。"

哆啦A梦笑着补充:

"而算法,正是帮我们找出那些'灵魂是否一致'的工具。"

相关推荐
oioihoii1 小时前
C++随机打乱函数:简化源码与原理深度剖析
开发语言·c++·算法
不知名。。。。。。。。1 小时前
分治算法---快排
算法
minji...2 小时前
数据结构 算法复杂度(1)
c语言·开发语言·数据结构·算法
凌肖战2 小时前
力扣网编程150题:加油站(贪心解法)
算法·leetcode·职场和发展
吃着火锅x唱着歌2 小时前
LeetCode 3306.元音辅音字符串计数2
算法·leetcode·c#
不見星空2 小时前
【leetcode】1751. 最多可以参加的会议数目 II
算法·leetcode
不見星空2 小时前
leetcode 每日一题 3439. 重新安排会议得到最多空余时间 I
算法·leetcode
SsummerC2 小时前
【leetcode100】下一个排列
python·算法·leetcode
black_blank2 小时前
st表 && csp37 第四题 集体锻炼
java·数据结构·算法
大数据魔法师3 小时前
基于Pandas和FineBI的昆明职位数据分析与可视化实现(五) - 基于随机森林算法预测职位分类
算法·pandas