同构字符串 图解题解
这道题到底在问什么
- s
- "cbaabc"
- t
- "zyxxyz"
- 输出
- true
最优解:一步一步想明白
- 3核心是一张 s→t 的映射表,再加一条铁律:映射必须双向一对一——同一个 s 字符只能对一个 t 字符,同一个 t 字符也只能被一个 s 字符占用。
- 4开始前:s→t 的映射表是空的。下面把 s 的字符放在格子里,t 的对应字符列在下方,一位一位地对齐检查。
- 5看第 0 位:s 这一格是 'c'(橙色),它在 t 里对应的字符是 'z'。下一步去映射表里查 'c' 之前记成了什么。
- 6'c' 之前没出现过,就把它记进映射表:'c' → 'z'(绿色新增)。同时占用 t 字符 'z',以后别的字母不能再映到它。
- 7到这里前 1 位都对得上,映射表里每个 s 字符对一个 t 字符、每个 t 字符也只被一个 s 字符占用,没有冲突。继续。
- 8看第 1 位:s 这一格是 'b'(橙色),它在 t 里对应的字符是 'y'。下一步去映射表里查 'b' 之前记成了什么。
- 9'b' 之前没出现过,就把它记进映射表:'b' → 'y'(绿色新增)。同时占用 t 字符 'y',以后别的字母不能再映到它。
- 10到这里前 2 位都对得上,映射表里每个 s 字符对一个 t 字符、每个 t 字符也只被一个 s 字符占用,没有冲突。继续。
- 11看第 2 位:s 这一格是 'a'(橙色),它在 t 里对应的字符是 'x'。下一步去映射表里查 'a' 之前记成了什么。
- 12'a' 之前没出现过,就把它记进映射表:'a' → 'x'(绿色新增)。同时占用 t 字符 'x',以后别的字母不能再映到它。
- 13到这里前 3 位都对得上,映射表里每个 s 字符对一个 t 字符、每个 t 字符也只被一个 s 字符占用,没有冲突。继续。
- 14看第 3 位:s 这一格是 'a'(橙色),它在 t 里对应的字符是 'x'。下一步去映射表里查 'a' 之前记成了什么。
- 15'a' 之前记过,映到 'x';这次它对的还是 'x',前后一致(命中高亮),通过,继续下一位。
- 16到这里前 4 位都对得上,映射表里每个 s 字符对一个 t 字符、每个 t 字符也只被一个 s 字符占用,没有冲突。继续。
- 17看第 4 位:s 这一格是 'b'(橙色),它在 t 里对应的字符是 'y'。下一步去映射表里查 'b' 之前记成了什么。
- 18'b' 之前记过,映到 'y';这次它对的还是 'y',前后一致(命中高亮),通过,继续下一位。
- 19到这里前 5 位都对得上,映射表里每个 s 字符对一个 t 字符、每个 t 字符也只被一个 s 字符占用,没有冲突。继续。
- 20看第 5 位:s 这一格是 'c'(橙色),它在 t 里对应的字符是 'z'。下一步去映射表里查 'c' 之前记成了什么。
- 21'c' 之前记过,映到 'z';这次它对的还是 'z',前后一致(命中高亮),通过,继续下一位。
- 22到这里前 6 位都对得上,映射表里每个 s 字符对一个 t 字符、每个 t 字符也只被一个 s 字符占用,没有冲突。继续。
- 23整串对齐完毕:c↔z、b↔y、a↔x 从头到尾都一致,也没有两个字母撞到同一个目标。s 和 t 同构,返回 true。
⚠️ 容易写错的地方
✗ 错:只查 s→t 一个方向
✓ 对:s→t 和 t→s 两个方向都要查
只查一个方向会漏掉「两个不同的 s 字符映到同一个 t 字符」的情况,比如 s="ab", t="aa" 会被误判为同构
✗ 错:先把两个映射都写进去再判断
✓ 对:先判冲突,没冲突再写入
写入之前必须用旧值比对,先写后判就比不出「这次和上次是否一致」了
✗ 错:忘了长度不等的情况
✓ 对:长度不同直接 false(zip 已隐含)
长度不一样根本无法逐位对齐,不可能同构
完整代码(Python / C++ / Java)
Python
def isIsomorphic(s, t):
st, ts = {}, {} # s→t 和 t→s 两张映射表
for a, b in zip(s, t):
if a in st and st[a] != b: # s 字符映出两种结果
return False
if b in ts and ts[b] != a: # 两个 s 字符撞同一个 t 字符
return False
st[a], ts[b] = b, a # 记下双向映射
return TrueC++
bool isIsomorphic(string s, string t){
unordered_map<char,char> st, ts;
for (int i = 0; i < s.size(); i++) {
char a = s[i], b = t[i];
if (st.count(a) && st[a] != b) return false;
if (ts.count(b) && ts[b] != a) return false;
st[a] = b; ts[b] = a;
}
return true;
}Java
public boolean isIsomorphic(String s, String t) {
Map<Character,Character> st = new HashMap<>(), ts = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
char a = s.charAt(i), b = t.charAt(i);
if (st.containsKey(a) && st.get(a) != b) return false;
if (ts.containsKey(b) && ts.get(b) != a) return false;
st.put(a, b); ts.put(b, a);
}
return true;
}复杂度
时间
O(n)
把两个串同步扫一遍,每位做常数次哈希查询,n 是串长
空间
O(1)
两张映射表最多各装下字符集大小(如 26 或 128)个键,与 n 无关
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 同构字符串 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么要维护两张映射表,一张不够吗?+
一张 s→t 只能保证「同一个 s 字符映出唯一结果」,挡不住「两个不同 s 字符映到同一个 t 字符」。加一张 t→s 才能保证反方向也一对一,即双射。
有没有不用哈希表的写法?+
有。可以记录每个字符「上一次出现的位置」,对齐时比较 s[i] 和 t[i] 的上次出现位置是否相同,不同则 false。本质仍是双向一致性,哈希表写法最直观。
同构和字母异位词有什么区别?+
异位词只看字符的「种类和个数」是否相同,不管顺序和位置;同构看的是「位置上的固定替换关系」,顺序很重要。两者考点完全不同。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 同构字符串 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。