🧠 小哆啦解题记——谁偷改了狗狗的台词?

小哆啦刷力扣第33天

🔍 题目:290. 单词规律 - 力扣(LeetCode)

给定一个 pattern 和一个字符串 s,判断 s 是否"遵循"这个规律 ------ 简单说,就是字母和单词之间存在"一一绑定关系",谁是谁的谁,不能乱认亲。


第一章:谁在背诵台词剧本?

"大雄!"

"你记得那部《狗狗的独白》电影吗?不是说台词 abba 代表 dog cat cat dog 吗?"

"我觉得有人改剧本了!"静香拿着一份神秘演出稿吼道:"abba → dog cat cat fish?!这鱼是来跑龙套的吗?"

哆啦A梦正好端着铜锣烧走过,一听就懂:"这是经典的模式匹配问题!"

大雄抓起键盘,打开力扣,敲出第一版剧本审核器:

arduino 复制代码
function wordPattern(pattern: string, s: string): boolean {
    const words = s.split(' ');
    if (pattern.length !== words.length) return false;

    const map = new Map<string, string>();
    for (let i = 0; i < pattern.length; i++) {
        const char = pattern[i];
        const word = words[i];

        if (map.has(char)) {
            if (map.get(char) !== word) return false;
        } else {
            map.set(char, word);
        }
    }
    return true;
}

运行 "abba" vs "dog cat cat fish"

竟然返回 true

哆啦A梦皱起了眉头:"大雄啊......你又只问了字母的想法,却没问问单词愿不愿意。"


第二章:双向绑定协议 · Part II

"映射是双向的。"哆啦A梦放下铜锣烧,冷静地分析。

数学意义上,这要求构建一个"双射函数(bijection) ":

  • 每个字母必须唯一对应一个单词(injective)
  • 每个单词也只能属于一个字母(surjective)

大雄灵光一闪:"那我再开一个 Map,反过来记录单词对应的字母!"

于是出现了进化版代码:

typescript 复制代码
function wordPattern(pattern: string, s: string): boolean {
    const words = s.trim().split(/\s+/);
    if (pattern.length !== words.length) return false;

    const p2w = new Map<string, string>();
    const w2p = new Map<string, string>();

    for (let i = 0; i < pattern.length; i++) {
        const p = pattern[i], w = words[i];

        if ((p2w.has(p) && p2w.get(p) !== w) ||
            (w2p.has(w) && w2p.get(w) !== p)) {
            return false;
        }

        p2w.set(p, w);
        w2p.set(w, p);
    }

    return true;
}

"这下不只是 pattern 在挑选 word,word 也能反审 pattern,恋爱自由,双向同意。"


第三章:测试现场 · 映射速查表

pattern s 结果 原因说明
"abba" "dog cat cat dog" ✅ true a→dogb→cat 成立
"abba" "dog cat cat fish" ❌ false a→dogb→cat vs a→fish冲突
"aaaa" "dog dog dog dog" ✅ true 所有人都爱 dog
"abba" "dog dog dog dog" ❌ false a→dog,但 b 也想要 dog,重婚
"abc" "dog cat" ❌ false pattern 和 s 长度不一致

第四章:映射错乱の真实世界悲剧

胖虎举手发问:"那如果我把 pattern 改成 "abcabc",s 改成 "one two three one two three" 呢?"

"可以!"大雄说,"每个字符绑定唯一的单词,每次都按顺序来,谁也不偷情。"

胖虎又说:"那我把 s 变成 "one two one one two one",pattern 还是 "abcabc"?"

啪------测试结果是:false

"a 本来绑定的是 one,b 是 two,但你现在让 b 也说 one,简直是角色乱窜现场演剧!"哆啦一巴掌拍醒胖虎。


第五章:深入字符词汇映射机制

🧠 底层原理拆解

  1. 字符映射本质上是一个键值映射表 Map<char, string>
  2. 字符个数 ≠ 单词个数 ➜ 提前返回 false,减少无谓计算;
  3. Set 无法满足双向性要求 ,所以用两个 Map 更明确;
  4. 若使用 JavaScript 对象 {},需要额外考虑键名冲突问题(如 __proto__),推荐使用 Map

第六章:映射是契约,不是猜测

"这道题,考察的不是你的字符串操作能力。"哆啦A梦闭上双眼道:

"它考察的是你是否真的理解'映射'这两个字的含义。"
映射是双向约定,是数学中的忠诚,是程序中的规则,是数据结构中的婚姻法。


📌 技术启示录:

关键词 含义
双射(bijection) 一一对应,映射双向唯一
Map 键值映射,适合字符与词之间的配对
Split + Trim 清洗输入,防止被多个空格或换行符破坏测试用例
预检优化 长度不等立即返回 false,避免陷入无效循环

📦 bonus:泛型映射工具(支持 Emoji、非ASCII 等复杂映射)

typescript 复制代码
function isBijectiveMapping<T extends string, U extends string>(
    source: T[],
    target: U[]
): boolean {
    if (source.length !== target.length) return false;

    const map1 = new Map<T, U>();
    const map2 = new Map<U, T>();

    for (let i = 0; i < source.length; i++) {
        const s = source[i], t = target[i];

        if ((map1.has(s) && map1.get(s) !== t) ||
            (map2.has(t) && map2.get(t) !== s)) {
            return false;
        }

        map1.set(s, t);
        map2.set(t, s);
    }

    return true;
}

"连外星文字都能绑定!"大雄惊呼,"我终于能匹配 🐶🐱🐸🐶 和 🍞🥓🥓🍞 了!"


🌌 终章:算法は秩序の约定

当所有测试通过,屏幕上浮现出大大的 "Accepted" 时,哆啦A梦放下代码本,感慨道:

"真正的规则,不是为了限制,而是为了彼此承诺。"

窗外星空如海,铜锣烧的香气飘进夜色。大雄低头看着 pattern,轻轻说:

"原来每一段字符,都是语言在试图写出内心的结构。"

而胖虎远处怒吼:"你们到底在写算法还是谈恋爱啊?!🐟 也值得被爱好吧?!"

相关推荐
a cool fish(无名)9 分钟前
8.1-使用向量存储值列表
人工智能·python·算法
茴香豆的茴121 分钟前
转码刷 LeetCode 笔记[1]:3.无重复字符的最长子串(python)
笔记·算法·leetcode
美团技术团队21 分钟前
ACL 2025 | 美团技术团队论文精选
人工智能·算法
xnglan36 分钟前
数据结构与算法:队列的表示和操作的实现
c语言·数据结构·算法·链表
快去睡觉~37 分钟前
力扣46:全排列
算法·leetcode·动态规划
蒋星熠40 分钟前
字母异位词分组(每天刷力扣hot100系列)
开发语言·c++·算法·leetcode·职场和发展
FirstFrost --sy1 小时前
数据结构之排序
c语言·数据结构·算法·排序算法
竹子_231 小时前
《零基础入门AI:传统机器学习核心算法(决策树、随机森林与线性回归)》
人工智能·算法·机器学习
Darkwanderor1 小时前
哈希相关的模拟实现
数据结构·c++·算法·哈希算法
阑梦清川1 小时前
树的存储方式--vector容器和链式前向星
算法