LeetCode 205 同构字符串

1. 题目

205. 同构字符串

题目描述

给定两个字符串 st,判断它们是否是同构的。

如果 s 中的字符可以按某种映射关系替换得到 t,那么这两个字符串是同构的。

每个出现的字符都应当映射到另一个字符,同时字符不能映射到多个字符,不同字符不能映射到同一个字符(双向唯一映射)。

字符串长度相等。

示例

输入:s = "egg", t = "add"

输出:true

输入:s = "foo", t = "bar"

输出:false

输入:s = "paper", t = "title"

输出:true

约束

  • (1 <= s.length <= 5 \times 10^4)

  • st 由任意 ASCII 字符组成,长度相等

2. 最佳解题思路描述(双向哈希映射,你的思路标准解法)

核心要求:双向一一映射

  1. 建立两张哈希表:

    • map1:s 字符 → t 字符(正向映射)

    • map2:t 字符 → s 字符(反向映射)

  2. 同步遍历两个字符串相同下标字符 c, c2:

    情况 1:c 已有正向映射,映射值必须等于 c2,否则不同构;

    情况 2:c 无正向映射,但 c2 已有反向映射,说明别的 s 字符占用了 c2,冲突,返回 false;

    情况 3:两边都无映射,同时存入两张哈希表;

  3. 全程无冲突则最后返回 true。

优势

逻辑直观,完美满足双向唯一映射规则;时间 (O(n)),n 为字符串长度。

3. 可优化代码(逻辑完全正确,仅规范、细节优化)

复制代码
class Solution {
public:
    bool isIsomorphic(string s, string t) {
        unordered_map<char,char>hash;
        unordered_map<char,char>hash2;
        for(int i = 0;i<s.size();i++){
            char c = s[i];
            char c2 = t[i];
            auto it = hash.find(c);
            auto it2 = hash2.find(c2);
            if(it != hash.end()){
                if(it->second != c2) return false;
            }
            else if(it2 != hash2.end()){
                if(it2->second != c) return false;
            }
            else{
                hash[c] = c2;
                hash2[c2] = c;
            }
        }
        return true;
    }
};

代码说明

  1. 正确性:无逻辑漏洞,所有测试用例均可通过,是标准双向哈希解法;

  2. 可优化规范点:

    • 变量名语义模糊:hashs2thash2t2s,可读性更强;

    • ASCII 字符范围 0~127,可用长度 128 数组替代 unordered_map,寻址更快、无哈希开销;

    • 循环改用范围 for 配合下标,或统一格式化空格;

    • 提前缓存字符串长度,避免多次调用s.size()

4. 两种优化标准代码

版本 1:数组映射(最优,ASCII 固定范围)

复制代码
class Solution {
public:
    bool isIsomorphic(string s, string t) {
        // ASCII共128个字符
        char s2t[128] = {0};
        char t2s[128] = {0};
        int n = s.size();
        for (int i = 0; i < n; ++i) {
            char c1 = s[i], c2 = t[i];
            int idx1 = c1, idx2 = c2;
            if (s2t[idx1] != 0) {
                if (s2t[idx1] != c2) return false;
            } else if (t2s[idx2] != 0) {
                if (t2s[idx2] != c1) return false;
            } else {
                s2t[idx1] = c2;
                t2s[idx2] = c1;
            }
        }
        return true;
    }
};

版本 2:规范哈希表版(哈希思路)

复制代码
#include <unordered_map>
using namespace std;
class Solution {
public:
    bool isIsomorphic(string s, string t) {
        unordered_map<char, char> s2t, t2s;
        int n = s.size();
        for (int i = 0; i < n; ++i) {
            char sc = s[i], tc = t[i];
            auto it1 = s2t.find(sc);
            auto it2 = t2s.find(tc);
            if (it1 != s2t.end()) {
                if (it1->second != tc) return false;
            } else if (it2 != t2s.end()) {
                if (it2->second != sc) return false;
            } else {
                s2t[sc] = tc;
                t2s[tc] = sc;
            }
        }
        return true;
    }
};

5. 总结

  1. 双向哈希思路完全正确,核心关键点:

    必须双向映射校验,只单向 map 会出错;

    反例:s="ab",t="aa",只用一张 map 会误判 true,两张 map 才能拦截;

  2. 字符为 ASCII 全集时,固定长度数组比 unordered_map 性能更好;

  3. 冲突判断顺序:先查正向映射,再查反向映射,任一不匹配直接 return false 提前终止。

6. 相关知识拓展

拓展 1:单向映射错误示范(易错坑)

只存 s→t,无法拦截多对一映射,过不了用例 s="ab",t="aa"

复制代码
// 错误代码
bool isIsomorphic(string s, string t) {
    unordered_map<char,char> mp;
    for(int i=0;i<s.size();i++){
        if(mp.count(s[i]) && mp[s[i]]!=t[i]) return false;
        mp[s[i]]=t[i];
    }
    return true;
}

拓展 2:同构进阶 LC290 单词规律

逻辑完全一致,只是映射对象从字符变为单词,同样需要双向哈希校验。

拓展 3:复杂度对比

  1. 双数组 ASCII 映射:(O(n)) 时间,(O(1)) 固定 128 空间(最优);

  2. 双 unordered_map 哈希:(O(n)) 平均时间,(O(n)) 最坏空间;

拓展 4:核心易错点复盘

  1. 只建立单向映射,无法处理多个字符映射到同一个字符的情况;

  2. 忘记同步更新两张映射表,导致反向校验失效;

  3. 哈希表 / 数组初始化不彻底,残留旧数据干扰判断。

相关推荐
影视飓风TIM20 分钟前
C++哈希表:unordered_set / unordered_map底层原理
c++·算法·哈希算法·散列表
在所不辞兄22 分钟前
【零基础学智能仿真-06】决策树——让模型自动发现力学失效阈值
算法·决策树·机器学习
啥都想学点的研究生38 分钟前
一篇文章讲清楚:C4.5决策树和CART决策树
算法·决策树·机器学习
DDXYcoder39 分钟前
万字解析动态内存从编译到运行
java·前端·算法
阳明山水43 分钟前
概念漂移分类与自适应策略解析
人工智能·深度学习·算法·机器学习·架构
欧特克_Glodon1 小时前
OpenCV计算机视觉开发入门与实践<二十九>:grabCut算法分割图像
opencv·算法·计算机视觉·图像分割·grabcut 算法
方方洛2 小时前
vllm教程-02-核心原理
人工智能·算法·vllm
OPEN-F2 小时前
C++并发编程:异步任务与线程池实战
开发语言·c++·算法
凉茶钱2 小时前
【数据结构】计数排序
数据结构·算法·排序算法