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

小哆啦刷力扣第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,轻轻说:

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

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

相关推荐
绝无仅有38 分钟前
企微审批对接错误与解决方案
后端·算法·架构
用户5040827858392 小时前
1. RAG 权威指南:从本地实现到生产级优化的全面实践
算法
Python×CATIA工业智造3 小时前
详细页智能解析算法:洞悉海量页面数据的核心技术
爬虫·算法·pycharm
无聊的小坏坏4 小时前
力扣 239 题:滑动窗口最大值的两种高效解法
c++·算法·leetcode
黎明smaly4 小时前
【排序】插入排序
c语言·开发语言·数据结构·c++·算法·排序算法
YuTaoShao4 小时前
【LeetCode 热题 100】206. 反转链表——(解法一)值翻转
算法·leetcode·链表
YuTaoShao4 小时前
【LeetCode 热题 100】142. 环形链表 II——快慢指针
java·算法·leetcode·链表
CCF_NOI.4 小时前
(普及−)B3629 吃冰棍——二分/模拟
数据结构·c++·算法
运器1235 小时前
【一起来学AI大模型】支持向量机(SVM):核心算法深度解析
大数据·人工智能·算法·机器学习·支持向量机·ai·ai编程