[LeetCode] 1247. Minimum Swaps to Make Strings Equal 交換字符使得字符串相同



You are given two strings s1 and s2 of equal length consisting of letters "x" and "y" only. Your task is to make these two strings equal to each other. You can swap any two characters that belong to different strings, which means: swap s1[i] and s2[j].

Return the minimum number of swaps required to make s1 and s2 equal, or return -1 if it is impossible to do so.

Example 1:

Input: s1 = "xx", s2 = "yy"
Output: 1
Explanation: Swap s1[0] and s2[1], s1 = "yx", s2 = "yx".

Example 2:

Input: s1 = "xy", s2 = "yx"
Output: 2
Explanation: Swap s1[0] and s2[0], s1 = "yy", s2 = "xx".
Swap s1[0] and s2[1], s1 = "xy", s2 = "xy".
Note that you can't swap s1[0] and s1[1] to make s1 equal to "yx", cause we can only swap chars in different strings.

Example 3:

Input: s1 = "xx", s2 = "xy"
Output: -1

Example 4:

Input: s1 = "xxyyxyxyxx", s2 = "xyyxyxxxyx"
Output: 4

Constraints:

  • 1 <= s1.length, s2.length <= 1000
  • s1, s2 only contain 'x' or 'y'.

這道題說是給了只有包含x和y兩種字母的字符串 s1 和 s2,現在為了使得二者變為相等,可以任意交換 s1 和 s2 中的兩個字符,現在問最小交換多少次可以使得二者相等,若無法變為相等,返回 -1。讀完題目之后,接下來就是要分析例子了,這道題的例子給的非常好,關鍵的解題思路都隱藏在了例子當中。首先來看第一個例子,當對應位置都是x和y的時候,只要對稱交換一下,就可以都變成 yx,這種情況只要一次替換。而對於例子2來說,對應位置互為相反,一個是 x->y,另一個是 y->x,這種情況需要兩次替換,先換成對應位置相同的情況,也就是例子1的情況,然后再替換一次,變為相等。

對於例子3來說,由於兩組映射既不相等,也不對稱,所以無論如何替換,都無法變為相等。例子4比較長,可以先移除相同位置的相同字符后,就變成了 xyxyyx 和 yxyxxy,此時的策略是,能用例子1的替換方法時就盡量先用,因為其只需一次替換,實在不行了再用例子2的替換方式。當然這取決於映射之間的關系,因為這里對應的位置的映射只有兩種:x->y 和 y->x,可以分別統計個數,這里的 x->y 映射有3個,y->x 映射也有3個。前面說了,應該先湊例子1的模式,則分別取出兩個 x->y 和 兩個 y->x 組成例子1的模式,總共消耗兩次替換即可,剩下了一個 x->y 和一個 y->x 映射,正好就是例子2的情況,需要兩次替換,總共需要4次替換操作。

分析到這里,題目也就沒啥難度了,博主最開始寫的時候,沒有注意看題目說只有x和y兩種字母,以為還有其他字母,所以寫了一個可以通用的解法,將兩個字母中間加個下划線,當作 HashMap 的 key,映射到其出現的次數,注意要先跳過相同的字母。映射數統計好了之后,就用前面分析的策略,先湊例子1的情況,把每個映射次數除以2,就能湊出的例子1情況的次數,直接加到結果 res 中,若還有剩余,則將個數加到另一個變量 cnt 中。最終 cnt 中的映射都是不同的,只能組成例子2的情況,若其為奇數,則說明有落單的,無法替換了,直接返回 -1,否則的話就返回 res+cnt 即可,參見代碼如下:


解法一:

class Solution {
public:
    int minimumSwap(string s1, string s2) {
        int res = 0, n = s1.size(), cnt = 0;
        unordered_map<string, int> m;
        for (int i = 0; i < n; ++i) {
            if (s1[i] == s2[i]) continue;
            ++m[string(1, s1[i]) + "_" + string(1, s2[i])];
        }
        for (auto &a : m) {
            res += a.second / 2;
            cnt += a.second % 2;
        }
        return cnt % 2 != 0 ? -1 : res + cnt;
    }
};

由於這道題只有x和y兩個字母,所以只需要統計 x->y 和 y->x 兩種映射即可,用兩個變量 xy 和 yx 來表示即可,不需要使用 HashMap。統計好了之后,判斷若 xy 和 yx 不同奇偶的話,說明一定有落單了,返回 -1,否則返回 xy/2 + yx/2 + (xy%2) * 2。這個表達式也不難理解,xy/2 + yx/2 就是例子1的情況所需要的替換次數,然后 xy % 2 可以知道 x->y 映射的奇偶,只有其是奇數的時候,才會有剩余,跟最后剩下的一個 y->x 映射組成例子2的情況即可,參見代碼如下:


解法二:

class Solution {
public:
    int minimumSwap(string s1, string s2) {
        int res = 0, n = s1.size(), xy = 0, yx = 0;
        for (int i = 0; i < n; ++i) {
            if (s1[i] == 'x' && s2[i] == 'y') ++xy;
            else if (s1[i] == 'y' && s2[i] == 'x') ++yx;
        }
        return (xy % 2 != yx % 2) ? -1 : (xy / 2 + yx / 2 + (xy % 2) * 2);
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1247


類似題目:

Determine if Two Strings Are Close


參考資料:

https://leetcode.com/problems/minimum-swaps-to-make-strings-equal/

https://leetcode.com/problems/minimum-swaps-to-make-strings-equal/discuss/419691/C%2B%2B-simple-solution

https://leetcode.com/problems/minimum-swaps-to-make-strings-equal/discuss/419874/Simply-Simple-Python-Solution-with-detailed-explanation


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM