1247. 交换字符使得字符串相同
有两个长度相同的字符串 s1 和 s2,且它们其中 只含有 字符 “x” 和 “y”,你需要通过「交换字符」的方式使这两个字符串相同。
每次「交换字符」的时候,你都可以在两个字符串中各选一个字符进行交换。
交换只能发生在两个不同的字符串之间,绝对不能发生在同一个字符串内部。也就是说,我们可以交换 s1[i] 和 s2[j],但不能交换 s1[i] 和 s1[j]。
最后,请你返回使 s1 和 s2 相同的最小交换次数,如果没有方法能够使得这两个字符串相同,则返回 -1 。
提示:
- 1 <= s1.length, s2.length <= 1000
- s1, s2 只包含 ‘x’ 或 ‘y’。
解题思路: 此题我没有做出来,看了题目的提示,提示1忽略所有已经配对的位置,未配对的位置影响结果,这个提示好理解,因为题目要求交换的次数尽量小,那么对于已经配对的位置自然没必要交换,那么我们要琢磨如何是未配对的位置交换的次数最少,提示2 (“xx”,“yy”)=>交换一次,(“xy”,“yx”)=>交换两次,那么表明可能最终要将交换的问题转为成这两种交换,提示3要想最终交换的次数尽可能少,那么我们需要尽可能使用(“xx”,“yy”)进行交换,未配对的再使用(“xy”,“yx”)进行交换。至此,我没有想出解决方案,最后我参考了题解中的解题思路,下面我们探索一下这种思路是怎么来的。
我们分析一下交换的基础,我们不能一对一交换,因为一对一字符的种类不同无法完成交换,比如"x"对"y",凡是能发生交换的都是多对多交换,而多对多交换要想交换成功,必须是偶数对的多对多交换,因此最终可以化归到两对两的交换上,因此把交换的基础转换到了(“xx”,“yy”)=>交换一次(交换I),(“xy”,“yx”)=>交换两次上(交换II),然后我们想,要想使最终的交换次数最少,那么我们要在序列中尽量凑齐交换I,比如若xy的对数是偶数,那么正好全部凑齐成交换I,若为奇数,则从xy中拿出一个,从yx中再拿出一个,凑成一对交换II,其他的因为是偶数对,正好可以凑齐交换I,因此也可达到最小次数交换。因此问题转换成数学公式计算问题(i.e.,要想得到交换次数,并不一定要对序列真正进行交换)。
遇到一些一开始没思路的题,要尝试着将大问题分解成小问题,把问题的基础base case分析出来,然后以基础base case再反推大问题的最优解。 贪心算法的很多解题思路都能找到与此类似的影子,慢慢体会吧~
在庞然大物面前,我们往往不知所措,此时我们需要深入庞然大物内部,分析它最本质的因素(取主要矛盾,略次要矛盾,先由繁入简,再由简推繁,先特殊再一般),在主要矛盾面前,在最精简的核心面前,事物的本质往往显现,而最优解也能暴露出来~
情至深处,胡诌一番~
class Solution {
public:
int minimumSwap(string s1, string s2) {
int xy = 0, yx = 0;
for (int i = 0; i < s1.size(); ++i) {
if (s1[i] == s2[i]) continue;
if (s1[i] == 'x') ++xy;
else ++yx;
}
if ((xy + yx) & 1) return -1;
else {
if (xy & 1) {
return (xy - 1 + yx - 1) / 2 + 2;
} else {
return (xy + yx) / 2;
}
}
}
};