📌  相关文章
📜  最少交换以将相似字符并排分组?

📅  最后修改于: 2021-05-24 20:36:53             🧑  作者: Mango

给定一个字符串,找到最少数量的交换(不一定相邻)以将其转换为并排具有相似字符的字符串。

例子:

这个想法是要考虑由两个元素之间的每次交换形成的所有排列,并且也不要交换两个元素。

C++
#include 
using namespace std;
  
// checks whether a string has similar characters side by side
bool sameCharAdj(string str)
{
    int n = str.length(), i;
    set st;
    st.insert(str[0]);
    for (i = 1; i < n; i++) {
  
        // If similar chars side by side, continue
        if (str[i] == str[i - 1])
            continue;
         
        // If we have found a char equal to current
        // char and does not exist side to it, 
        // return false
        if (st.find(str[i]) != st.end())
            return false;
  
        st.insert(str[i]);
    }
    return true;
}
  
// counts min swap operations to convert a string 
// that has similar characters side by side
int minSwaps(string str, int l, int r, int cnt, int minm)
{
   // Base case 
   if (l == r) {
        if (sameCharAdj(str))
            return cnt;
        else
            return INT_MAX;
    }
     
    for (int i = l + 1; i <= r; i++) {
        swap(str[i], str[l]);
        cnt++;
  
        // considering swapping of i and l chars 
        int x = minSwaps(str, l + 1, r, cnt, minm); 
  
        // Backtrack
        swap(str[i], str[l]);
        cnt--;
  
        // not considering swapping of i and l chars
        int y = minSwaps(str, l + 1, r, cnt, minm);
  
        // taking min of above two 
        minm = min(minm, min(x, y)); 
    }
  
    return minm;
}
  
// Driver code
int main()
{
    string str = "abbaacb";
    int n = str.length(), cnt = 0, minm = INT_MAX;
    cout << minSwaps(str, 0, n - 1, cnt, minm) << endl;
    return 0;
}


Java
import java.util.*;
  
class GFG {
  
// checks whether a String has similar characters side by side
    static boolean sameJavaharAdj(char str[]) {
        int n = str.length, i;
        TreeSet st = new TreeSet<>();
        st.add(str[0]);
        for (i = 1; i < n; i++) {
  
            // If similar chars side by side, continue
            if (str[i] == str[i - 1]) {
                continue;
            }
  
            // If we have found a char equal to current
            // char and does not exist side to it, 
            // return false
            if (st.contains(str[i]) & (str[i] != st.last())) {
                return false;
            }
            st.add(str[i]);
        }
        return true;
    }
  
// counts min swap operations to convert a String 
// that has similar characters side by side
    static int minSwaps(char str[], int l, int r, int cnt, int minm) {
        // Base case 
        if (l == r) {
            if (sameJavaharAdj(str)) {
                return cnt;
            } else {
                return Integer.MAX_VALUE;
            }
        }
  
        for (int i = l + 1; i <= r; i++) {
            swap(str, i, l);
            cnt++;
  
            // considering swapping of i and l chars 
            int x = minSwaps(str, l + 1, r, cnt, minm);
  
            // Backtrack
            swap(str, i, l);
            cnt--;
  
            // not considering swapping of i and l chars
            int y = minSwaps(str, l + 1, r, cnt, minm);
  
            // taking Math.min of above two 
            minm = Math.min(minm, Math.min(x, y));
        }
  
        return minm;
    }
  
    static void swap(char[] arr, int i, int j) {
        char temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
// Driver code
  
    public static void main(String[] args) {
        String str = "abbaacb";
        int n = str.length(), cnt = 0, minm = Integer.MAX_VALUE;
        System.out.print(minSwaps(str.toCharArray(), 0, n - 1, cnt, minm));;
    }
}
// This code is contributed Rajput-Ji


Python3
# Python3 implementation of the approach
from sys import maxsize
  
# checks whether a string has 
# similar characters side by side
def sameCharAdj(string):
    n = len(string)
    st = set()
    st.add(string[0])
  
    for i in range(1, n):
  
        # If similar chars side by side, continue
        if string[i] == string[i - 1]:
            continue
  
        # If we have found a char equal to current
        # char and does not exist side to it,
        # return false
        if string[i] in st:
            return False
  
        st.add(string[i])
    return True
  
# counts min swap operations to convert a string
# that has similar characters side by side
def minSwaps(string, l, r, cnt, minm):
  
    # Base case
    if l == r:
        if sameCharAdj(string):
            return cnt
        else:
            return maxsize
  
    for i in range(l + 1, r + 1, 1):
        string[i], string[l] = string[l], string[i]
        cnt += 1
  
        # considering swapping of i and l chars
        x = minSwaps(string, l + 1, r, cnt, minm)
  
        # Backtrack
        string[i], string[l] = string[l], string[i]
        cnt -= 1
  
        # not considering swapping of i and l chars
        y = minSwaps(string, l + 1, r, cnt, minm)
  
        # taking min of above two
        minm = min(minm, min(x, y))
  
    return minm
  
# Driver Code
if __name__ == "__main__":
    string = "abbaacb"
    string = list(string)
  
    n = len(string)
    cnt = 0
    minm = maxsize
    print(minSwaps(string, 0, n - 1, cnt, minm))
  
# This code is contributed by
# sanjeev2552


C#
using System;
using System.Collections.Generic;
  
class GFG 
{
  
    // checks whether a String has similar 
    // characters side by side
    static bool sameJavaharAdj(char []str)
    {
        int n = str.Length, i;
        HashSet st = new HashSet();
        st.Add(str[0]);
        for (i = 1; i < n; i++) 
        {
  
            // If similar chars side by side, continue
            if (str[i] == str[i - 1]) 
            {
                continue;
            }
  
            // If we have found a char equal to current
            // char and does not exist side to it, 
            // return false
            if (st.Contains(str[i]) & !st.Equals(str[i])) 
            {
                return false;
            }
            st.Add(str[i]);
        }
        return true;
    }
  
    // counts min swap operations to convert a String 
    // that has similar characters side by side
    static int minSwaps(char []str, int l, int r, 
                                int cnt, int minm) 
    {
        // Base case 
        if (l == r) 
        {
            if (sameJavaharAdj(str))
            {
                return cnt;
            } 
            else
            {
                return int.MaxValue;
            }
        }
  
        for (int i = l + 1; i <= r; i++)
        {
            swap(str, i, l);
            cnt++;
  
            // considering swapping of i and l chars 
            int x = minSwaps(str, l + 1, r, cnt, minm);
  
            // Backtrack
            swap(str, i, l);
            cnt--;
  
            // not considering swapping of i and l chars
            int y = minSwaps(str, l + 1, r, cnt, minm);
  
            // taking Math.min of above two 
            minm = Math.Min(minm, Math.Min(x, y));
        }
  
        return minm;
    }
  
    static void swap(char[] arr, int i, int j) 
    {
        char temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
      
    // Driver code
    public static void Main()
    {
        String str = "abbaacb";
        int n = str.Length, cnt = 0, minm = int.MaxValue;
        Console.WriteLine(minSwaps(str.ToCharArray(), 0,
                                    n - 1, cnt, minm));;
    }
}
  
// This code is contributed mits


输出:
2

时间复杂度:递归是T(n)= 2n * T(n-1)+ O(n)
因此时间复杂度大于O((2 * n)!)