LeetCode 2839. 判断通过操作能否让字符串相等 I
题目描述
给你两个长度相等的字符串 s1 和 s2。
你可以任意次 交换 s1 中 下标同为奇数 或 下标同为偶数 的字符。
判断能否通过若干次这样的交换,使得 s1 变成 s2。
示例 1:
输入:s1 = "abcd", s2 = "cdab"
输出:true
解释:交换下标 0 和 2 得到 "cbad",再交换下标 1 和 3 得到 "cdab"。
示例 2:输入:s1 = "abcd", s2 = "acbd"
输出:false
解释:奇数位字符集合不同。
算法思路
关键观察:
- 只能交换 奇数下标 之间的字符,或者 偶数下标 之间的字符。
- 因此,奇数位上的字符 永远无法跑到偶数位上,反之亦然。
- 问题转化为:
s1中所有奇数下标上的字符组成(频次)必须与s2中所有奇数下标上的字符组成完全相同。s1中所有偶数下标上的字符组成(频次)必须与s2中所有偶数下标上的字符组成完全相同。
具体做法
- 创建两个二维数组
cnt1[2][26]和cnt2[2][26]。- 第一维
0表示偶数下标,1表示奇数下标。 - 第二维记录对应位置上每个字母出现的次数。
- 第一维
- 遍历字符串,根据下标奇偶性,分别统计
s1和s2中每个字母的频次。 - 比较两个统计数组是否完全一致。若一致则返回
true,否则false。
代码实现(C++)
cpp
class Solution {
public:
bool canBeEqual(string s1, string s2) {
int cnt1[2][26]{}; // 统计 s1 中奇偶位置的字母频次
int cnt2[2][26]{}; // 统计 s2 中奇偶位置的字母频次
for (int i = 0; i < s1.length(); i++) {
cnt1[i % 2][s1[i] - 'a']++;
cnt2[i % 2][s2[i] - 'a']++;
}
// 内存比较两个统计数组是否相等
return memcmp(cnt1, cnt2, sizeof(cnt1)) == 0;
}
};
复杂度分析
- 时间复杂度 :O(n)
一次遍历字符串,n 为字符串长度。 - 空间复杂度 :O(1)
只使用了固定大小的数组2×26,与输入规模无关。
正确性证明
- 必要性:若
s1能通过合法交换变成s2,则奇数位集合与偶数位集合分别保持不变,因此频次统计必然相同。 - 充分性:若奇偶位上的字符频次分别相同,则我们可以在奇数位内任意排列(通过相邻交换实现任意排列),偶数位同理,因此总能构造出
s2。
总结
本题的关键在于将交换限制转化为奇偶位置的独立性,从而用简单的计数比较代替复杂的搜索。这种"奇偶位分离"的思想在字符串处理问题中非常实用。