1247. 交换字符使得字符串相同
难度中等162收藏分享切换为英文接收动态反馈
有两个长度相同的字符串 s1
和 s2
,且它们其中 只含有 字符 "x"
和 "y"
,你需要通过「交换字符」的方式使这两个字符串相同。
每次「交换字符」的时候,你都可以在两个字符串中各选一个字符进行交换。
交换只能发生在两个不同的字符串之间,绝对不能发生在同一个字符串内部。也就是说,我们可以交换 s1[i]
和 s2[j]
,但不能交换 s1[i]
和 s1[j]
。
最后,请你返回使 s1
和 s2
相同的最小交换次数,如果没有方法能够使得这两个字符串相同,则返回 -1
。
示例 1:
输入:s1 = "xx", s2 = "yy" 输出:1 解释: 交换 s1[0] 和 s2[1],得到 s1 = "yx",s2 = "yx"。
示例 2:
输入:s1 = "xy", s2 = "yx" 输出:2 解释: 交换 s1[0] 和 s2[0],得到 s1 = "yy",s2 = "xx" 。 交换 s1[0] 和 s2[1],得到 s1 = "xy",s2 = "xy" 。 注意,你不能交换 s1[0] 和 s1[1] 使得 s1 变成 "yx",因为我们只能交换属于两个不同字符串的字符。
示例 3:
输入:s1 = "xx", s2 = "xy" 输出:-1
示例 4:
输入:s1 = "xxyyxyxyxx", s2 = "xyyxyxxxyx" 输出:4
提示:
1 <= s1.length, s2.length <= 1000
s1, s2
只包含'x'
或'y'
。
思路:首先需要明确的一点是,如果对于索引idx,s1[idx]==s2[idx]的情况下,我们是不用动的,这样才符合我们需要的最小交换次数的要求。现在我们来看看在s1[idx]与s2[idx]不相同的情况:
A. s1[idx]=='x',s2[idx]=='y',此种情况记为xy
如上图所示,在这种情况下,可以交换s1[idx_1]与s2[idx_2]或者交换s1[idx_2]与s2[idx_1],即将两个xy进行一次置换可以消去两个xy模式。
B. s1[idx]=='y',s2[idx]=='x',此种情况记为yx
与上类似,这种情况可以将两个yx进行一次置换可以消去两个yx模式。
以上讨论限于都为偶数的情况,那么对于奇数情况呢?
首先必须明确的是,如果xy和yx模式的个数一个为奇数一个为偶数就不可能通过交换将两者变成相同字符串。举例来说,一个xy模式,要么使用另一个xy模式与之采用一步交换消去,要么使用yx模式与之采用两步交换消去,如果只有一个xy模式,是没有办法消去的。
xy模式与yx模式的两步消除法在题目中已经给出了例子:
输入:s1 = "xy", s2 = "yx"
输出:2
解释: 交换 s1[0] 和 s2[0],得到 s1 = "yy",s2 = "xx" 。 交换 s1[0] 和 s2[1],得到 s1 = "xy",s2 = "xy" 。 注意,你不能交换 s1[0] 和 s1[1] 使得 s1 变成 "yx",因为我们只能交换属于两个不同字符串的字符。
因此我们已经有了算法流程:
1.统计xy、yx模式的出现次数
2.如果xy模式和yx模式的和为奇数,势必为一个奇数一个偶数,此时一定没有办法成功交换,返回-1
3.如果二者都为偶数,那么需要的最小交换次数为xy_num / 2 + yx_num / 2
4.如果为两个奇数,那么需要的最小交换次数为xy_num / 2 + yx_num / 2 + 2
class Solution {
public:
int minimumSwap(string s1, string s2) {
if(s1.length() != s2.length()) return -1;
int xy_num = 0, yx_num = 0, idx;
for(idx = s1.length() - 1; idx >= 0; -- idx){
if(s1[idx] == 'x' && s2[idx] == 'y'){
++ xy_num;
}else if(s1[idx] == 'y' && s2[idx] == 'x'){
++ yx_num;
}
}
if((xy_num + yx_num) & 1){
return -1;
}//必然是两个偶数或者两个奇数 如果是两个偶数则只需要各自和各自交换 如果是两个奇数 则最后+2
return xy_num / 2 + yx_num / 2 + (xy_num & 1 ? 2 : 0);
}
};