交换字符使得字符串相同 图解题解
这道题到底在问什么
- 输入
- s1 = "xx", s2 = "yy"
- 输出
- 1
- 输入
- s1 = "xy", s2 = "yx"
- 输出
- 2
- 输入
- s1 = "xx", s2 = "xy"
- 输出
- -1
- 输入
- 本节演示 s1 = "xxyxyxxy", s2 = "yxxyxxyx"
- 输出
- 4
最优解:一步一步想明白
- 3记牢一句话:不匹配分 xy、yx 两类,同类两两一次换掉,最后落单的一对 xy 和 yx 要两次。下面每帧都在套它。
- 4上面这排是把 s1 和 s2 对齐后摆出来的 8 个位置,每个格子竖线左边是 s1 的字符、右边是 s2 的字符。准备两个计数器,xy 记「s1 是 x、s2 是 y」的位置数,yx 记「s1 是 y、s2 是 x」的位置数,现在都清成 0。从第 0 位开始,一位一位往右看。
- 5看第 0 位:s1 这位是 "x",s2 这位是 "y"。两个字符不一样,得分个类。
- 6这位 s1 是 "x"、s2 是 "y",属于 xy 类,标成绿色,xy 计数加一,现在 xy = 1。
- 7看第 1 位:s1 这位是 "x",s2 这位是 "x"。两个字符一样。
- 8这位 s1 和 s2 都是 "x",本来就一样,不用动它,标成蓝色跳过,计数都不变。
- 9看第 2 位:s1 这位是 "y",s2 这位是 "x"。两个字符不一样,得分个类。
- 10这位 s1 是 "y"、s2 是 "x",属于 yx 类,标成红色,yx 计数加一,现在 yx = 1。
- 11看第 3 位:s1 这位是 "x",s2 这位是 "y"。两个字符不一样,得分个类。
- 12这位 s1 是 "x"、s2 是 "y",属于 xy 类,标成绿色,xy 计数加一,现在 xy = 2。
- 13看第 4 位:s1 这位是 "y",s2 这位是 "x"。两个字符不一样,得分个类。
- 14这位 s1 是 "y"、s2 是 "x",属于 yx 类,标成红色,yx 计数加一,现在 yx = 2。
- 15看第 5 位:s1 这位是 "x",s2 这位是 "x"。两个字符一样。
- 16这位 s1 和 s2 都是 "x",本来就一样,不用动它,标成蓝色跳过,计数都不变。
- 17看第 6 位:s1 这位是 "x",s2 这位是 "y"。两个字符不一样,得分个类。
- 18这位 s1 是 "x"、s2 是 "y",属于 xy 类,标成绿色,xy 计数加一,现在 xy = 3。
- 19看第 7 位:s1 这位是 "y",s2 这位是 "x"。两个字符不一样,得分个类。
- 20这位 s1 是 "y"、s2 是 "x",属于 yx 类,标成红色,yx 计数加一,现在 yx = 3。
- 218 个位置全看完:绿色 xy 类有 3 个(第 0、3、6 位),红色 yx 类有 3 个(第 2、4、7 位),蓝色相同位跳过 2 个。不匹配合计 6 个,是偶数,说明能配平、有解。下面开始配对算次数。
- 22先看绿色 xy 类。第 0 位和第 3 位都是「s1 是 x、s2 是 y」。把 s1 第 0 位的 "x" 和 s2 第 3 位的 "y" 对调一次,这两位就同时对齐了。两个同类不匹配,一次交换全消掉,已用 1 次。
- 23xy 类一共 3 个,两两配走一对,还剩第 6 位这一个 xy 落单,先放着,等会儿和落单的 yx 一起处理。
- 24再看红色 yx 类。第 2 位和第 4 位都是「s1 是 y、s2 是 x」,同样一次交换就能把这两位一起摆平,累计已用 2 次。
- 25yx 类也是 3 个,配走一对后剩第 7 位这一个 yx 落单。现在台面上剩一个 xy(第 6 位)和一个 yx(第 7 位)。
- 26落单这一个 xy 和一个 yx 不同类,不能一次解决。得先花一次交换把其中一个变成和另一个同类(比如把它俩先弄成两个 yx),再花一次消掉,这一对总共 2 次。加上前面两次,累计 4 次。
- 27汇总:xy 类 3 个出 1 对、yx 类 3 个出 1 对,各 1 次;最后落单的 xy 加 yx 那一对 2 次。合起来 1 加 1 加 2 等于 4 次,跟开头说的答案对上了。
⚠️ 容易写错的地方
✗ 错:想真的去模拟交换、搜索最少步数,套上 BFS 或回溯
✓ 对:只数 xy 和 yx 两类不匹配,套公式直接出答案
消除不匹配只有两种固定方式:同类两个一次、跨类一对两次,数量定了次数就定了,根本不用搜索
✗ 错:忘了判无解,所有情况都硬算出一个数
✓ 对:先判 xy 加 yx 是不是奇数,是就立刻返回 -1
不匹配只能成对消掉,总数是奇数时永远剩一个配不出去,等价于两串里 "x" 的总数为奇数,无论怎么换都不可能相同
✗ 错:把落单的一个 xy 加一个 yx 也当成一次交换
✓ 对:这一对要两次:先换成同类,再消掉
像 s1="xy"、s2="yx",直接换一次只会换汤不换药,得先花一次把它变成两个同类的不匹配,再花一次,合计两次
完整代码(Python / C++ / Java)
Python
from __future__ import annotations
from typing import *
from collections import *
from functools import *
from itertools import *
from math import *
from heapq import *
from bisect import *
class Solution:
def minimumSwap(self, s1: str, s2: str) -> int:
xy = yx = 0
for a, b in zip(s1, s2):
xy += a < b
yx += a > b
if (xy + yx) % 2:
return -1
return xy // 2 + yx // 2 + xy % 2 + yx % 2C++
#include <algorithm>
#include <array>
#include <cctype>
#include <climits>
#include <cmath>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
class Solution {
public:
int minimumSwap(string s1, string s2) {
int xy = 0, yx = 0;
for (int i = 0; i < s1.size(); ++i) {
char a = s1[i], b = s2[i];
xy += a < b;
yx += a > b;
}
if ((xy + yx) % 2) {
return -1;
}
return xy / 2 + yx / 2 + xy % 2 + yx % 2;
}
};Java
import java.util.*;
class Solution {
public int minimumSwap(String s1, String s2) {
int xy = 0, yx = 0;
for (int i = 0; i < s1.length(); ++i) {
char a = s1.charAt(i), b = s2.charAt(i);
if (a < b) {
++xy;
}
if (a > b) {
++yx;
}
}
if ((xy + yx) % 2 == 1) {
return -1;
}
return xy / 2 + yx / 2 + xy % 2 + yx % 2;
}
}复杂度
时间
O(n)
n 为字符串长度。两串对齐后每个位置只比一次、记一次,整体是一遍线性扫描,最后做几下常数运算
空间
O(1)
自始至终只用 xy 和 yx 两个整数计数器,没有额外的数组或栈,峰值占用是常数,跟串多长无关
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 交换字符使得字符串相同 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么两个同类不匹配一次交换就够,而一个 xy 加一个 yx 要两次?+
两个同类比如两个 xy,意味着两处都是 s1 为 x、s2 为 y。把一处 s1 的 x 和另一处 s2 的 y 对调,两处立刻都对齐,一次就行。而一个 xy 配一个 yx 方向相反,直接对调任意两个字符都没法让两处同时对齐,只能先花一次把它俩变成同类,再花一次消掉,所以是两次。
什么时候返回 -1,背后的道理是什么?+
当 xy 加 yx 是奇数时返回 -1。因为不匹配只能成对消除,总数是奇数就永远剩一个配不出去。换个角度看,它等价于两个串里 "x" 的总数是奇数,这时无论怎么跨串交换都凑不出逐位相同,所以无解。
这题的时间和空间复杂度是多少?+
时间 O(n),n 是字符串长度,两串对齐后每位只比一次、记一次。空间 O(1),全程只用 xy 和 yx 两个整数计数器,不开额外数组,占用是常数。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 交换字符使得字符串相同 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。