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

📅 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梦笑着补充:

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

相关推荐
搞科研的小刘选手15 分钟前
【ISSN/ISBN双刊号】第三届电力电子与人工智能国际学术会议(PEAI 2026)
图像处理·人工智能·算法·电力电子·学术会议
拉姆哥的小屋18 分钟前
从混沌到秩序:条件扩散模型在图像转换中的哲学与技术革命
人工智能·算法·机器学习
Sammyyyyy22 分钟前
DeepSeek v3.2 正式发布,对标 GPT-5
开发语言·人工智能·gpt·算法·servbay
sin_hielo1 小时前
leetcode 2110
数据结构·算法·leetcode
Jay20021111 小时前
【机器学习】33 强化学习 - 连续状态空间(DQN算法)
人工智能·算法·机器学习
panzer_maus1 小时前
归并排序的简单介绍
java·数据结构·算法
cici158742 小时前
二值化断裂裂缝的智能拼接算法
人工智能·算法·计算机视觉
麦格芬2302 小时前
LeetCode 763 划分字母区间
算法·leetcode·职场和发展
福尔摩斯张2 小时前
C++核心特性精讲:从C语言痛点出发,掌握现代C++编程精髓(超详细)
java·linux·c语言·数据结构·c++·驱动开发·算法
涛涛北京3 小时前
【强化学习实验】- 策略梯度算法
人工智能·算法