📌  相关文章
📜  通过重新排列字符从给定字符串获得最大回文字符串

📅  最后修改于: 2021-04-29 14:14:52             🧑  作者: Mango

给定两个字符串SP ,任务是通过重新排列字符后从给定的字符串SP中选择字符来找到最大的回文字符串。
注意:如果可能有许多答案,请在词典上找到具有最大长度的最小T。

例子:

方法:我们的想法是采取一切与字符串SP中存在甚至多次分别的字符。作为子字符串,两个字符串的AB都具有在SP中出现偶数次的所有字符,从而成为父字符串最大的回文。步骤如下:

  1. 从字符串SP中选取一个字符,这样它们将分别出现在从每个字符串取出的回文中。将唯一元素放在T的中间。
  2. 从子字符串AB中获取唯一元素的可能情况是:
    • 如果在AB中都存在一个唯一元素,则应同时使用它们,因为这会使T的长度增加2
    • 如果在SP中都存在唯一元素,但不存在相同元素,则采用较小的元素,因为这将使字典上的最小回文数T最小。
    • 如果两者均不存在唯一元素,则仅使用AB中的元素构成字符串T。
  3. 使用无序映射可以计算在父字符串偶数次出现的字符数。另外,使用另一个映射来计算要使用的字符数T。

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
 
// Function to find largest palindrome
// possible from S and P after rearranging
// characters to make palindromic string T
string mergePalindromes(string S, string P)
{
 
    // Using unordered_map to store
    // frequency of elements
    // mapT will have freq of elements of T
    unordered_map mapS, mapP, mapT;
 
    // Size of both the strings
    int n = S.size(), m = P.size();
 
    for (int i = 0; i < n; i++) {
        mapS[S[i]]++;
    }
    for (int i = 0; i < m; i++) {
        mapP[P[i]]++;
    }
 
    // Take all character in mapT which
    // occur even number of times in
    // respective strings & simultaneously
    // update number of characters left in map
    for (char i = 'a'; i <= 'z'; i++) {
 
        if (mapS[i] % 2 == 0) {
            mapT[i] += mapS[i];
            mapS[i] = 0;
        }
        else {
            mapT[i] += mapS[i] - 1;
            mapS[i] = 1;
        }
 
        if (mapP[i] % 2 == 0) {
            mapT[i] += mapP[i];
            mapP[i] = 0;
        }
        else {
            mapT[i] += mapP[i] - 1;
            mapP[i] = 1;
        }
    }
 
    // Check if a unique character is
    // present in both string S and P
    int check = 0;
 
    for (char i = 'a'; i <= 'z'; i++) {
        if (mapS[i] > 0 && mapP[i] > 0) {
            mapT[i] += 2;
            check = 1;
            break;
        }
    }
 
    // Making string T in two halves
    // half1 - first half
    // half2 - second half
    string half1 = "", half2 = "";
 
    for (char i = 'a'; i <= 'z'; i++) {
        for (int j = 0; (2 * j) < mapT[i]; j++) {
            half1 += i;
            half2 += i;
        }
    }
 
    // Reverse the half2 to attach with half1
    // to make palindrome T
    reverse(half2.begin(), half2.end());
 
    // If same unique element is present
    // in both S and P, then taking that only
    // which is already taken through mapT
    if (check) {
        return half1 + half2;
    }
 
    // If same unique element is not
    // present in S and P, then take
    // characters that make string T
    // lexicographically smallest
    for (char i = 'a'; i <= 'z'; i++) {
        if (mapS[i] > 0 || mapP[i] > 0) {
            half1 += i;
            return half1 + half2;
        }
    }
 
    // If no unique element is
    // present in both string S and P
    return half1 + half2;
}
 
// Driver Code
int main()
{
    // Given two strings S and P
    string S = "aeabb";
    string P = "dfedf";
 
    // Function Call
    cout << mergePalindromes(S, P);
    return 0;
}


Java
// Java program for the above approach
import java.util.*;
import java.lang.*;
 
class GFG{
 
// Function to find largest palindrome
// possible from S and P after rearranging
// characters to make palindromic string T
static String mergePalindromes(StringBuilder S,
                               StringBuilder P)
{
    // Using unordered_map to store
    // frequency of elements
    // mapT will have freq of elements of T
    Map mapS = new HashMap<>(),
                            mapP = new HashMap<>(),
                            mapT = new HashMap<>();
 
    // Size of both the strings
    int n = S.length(), m = P.length();
 
    for(int i = 0; i < n; i++)
    {
        mapS.put(S.charAt(i),
        mapS.getOrDefault(S.charAt(i), 0) + 1);
    }
    for(int i = 0; i < m; i++)
    {
        mapP.put(P.charAt(i),
        mapP.getOrDefault(P.charAt(i), 0) + 1);
    }
 
    // Take all character in mapT which
    // occur even number of times in
    // respective strings & simultaneously
    // update number of characters left in map
    for(char i = 'a'; i <= 'z'; i++)
    {
        if (mapS.getOrDefault(i, 0) % 2 == 0)
        {
           mapT.put(i,mapT.getOrDefault(i, 0) +
           mapS.getOrDefault(i, 0));
           mapS.put(i, 0);
        }
        else
        {
            mapT.put(i,mapT.getOrDefault(i, 0) +
            mapS.getOrDefault(i, 0) - 1);
            mapS.put(i, 1);
        }
 
        if (mapP.getOrDefault(i, 0) % 2 == 0)
        {
            mapT.put(i, mapT.getOrDefault(i, 0) +
            mapP.getOrDefault(i, 0));
            mapP.put(i, 0);
        }
        else
        {
            mapT.put(i, mapT.getOrDefault(i, 0) +
            mapP.getOrDefault(i, 0) - 1);
            mapP.put(i, 1);
        }
    }
 
    // Check if a unique character is
    // present in both string S and P
    int check = 0;
 
    for(char i = 'a'; i <= 'z'; i++)
    {
        if (mapS.getOrDefault(i, 0) > 0 &&
            mapP.getOrDefault(i, 0) > 0)
        {
            mapT.put(i, mapT.getOrDefault(i, 0) + 2);
            check = 1;
            break;
        }
    }
 
    // Making string T in two halves
    // half1 - first half
    // half2 - second half
    StringBuilder half1 = new StringBuilder(),
                  half2 = new StringBuilder();
 
    for(char i = 'a'; i <= 'z'; i++)
    {
        for(int j = 0;
           (2 * j) < mapT.getOrDefault(i, 0);
                j++)
        {
            half1.append(i);
            half2.append(i);
        }
    }
 
    // Reverse the half2 to attach with half1
    // to make palindrome T
    StringBuilder tmp = half2.reverse();
 
    // If same unique element is present
    // in both S and P, then taking that only
    // which is already taken through mapT
    if (check == 1)
    {
        return half1.append(tmp).toString();
    }
 
    // If same unique element is not
    // present in S and P, then take
    // characters that make string T
    // lexicographically smallest
    for(char i = 'a'; i <= 'z'; i++)
    {
        if (mapS.getOrDefault(i, 0) > 0 ||
            mapP.getOrDefault(i, 0) > 0)
        {
            half1.append(i);
            return half1.append(tmp).toString();
        }
    }
 
    // If no unique element is
    // present in both string S and P
    return half1.append(tmp).toString();
}
 
// Driver code
public static void main (String[] args)
{
     
    // Given two strings S and P
    StringBuilder S = new StringBuilder("aeabb");
    StringBuilder P = new StringBuilder("dfedf");
     
    // Function call
    System.out.println(mergePalindromes(S, P));
}
}
 
// This code is contributed by offbeat


Python3
# Python3 program for the above approach
from collections import defaultdict
 
# Function to find largest palindrome
# possible from S and P after rearranging
# characters to make palindromic string T
def mergePalindromes(S, P):
 
    # Using unordered_map to store
    # frequency of elements
    # mapT will have freq of elements of T
    mapS = defaultdict(lambda : 0)
    mapP = defaultdict(lambda : 0)
    mapT = defaultdict(lambda : 0)
 
    # Size of both the strings
    n = len(S)
    m = len(P)
 
    for i in range(n):
        mapS[ord(S[i])] += 1
 
    for i in range(m):
        mapP[ord(P[i])] += 1
 
    # Take all character in mapT which
    # occur even number of times in
    # respective strings & simultaneously
    # update number of characters left in map
    for i in range(ord('a'), ord('z') + 1):
        if(mapS[i] % 2 == 0):
            mapT[i] += mapS[i]
            mapS[i] = 0
        else:
            mapT[i] += mapS[i] - 1
            mapS[i] = 1
 
        if (mapP[i] % 2 == 0):
            mapT[i] += mapP[i]
            mapP[i] = 0
        else:
            mapT[i] += mapP[i] - 1
            mapP[i] = 1
 
    # Check if a unique character is
    # present in both string S and P
    check = 0
 
    for i in range(ord('a'), ord('z') + 1):
        if (mapS[i] > 0 and mapP[i] > 0):
            mapT[i] += 2
            check = 1
            break
 
    # Making string T in two halves
    # half1 - first half
    # half2 - second half
    half1, half2 = "", ""
 
    for i in range(ord('a'), ord('z') + 1):
        j = 0
        while((2 * j) < mapT[i]):
            half1 += chr(i)
            half2 += chr(i)
            j += 1
 
    # Reverse the half2 to attach with half1
    # to make palindrome
    half2 = half2[::-1]
 
    # If same unique element is present
    # in both S and P, then taking that only
    # which is already taken through mapT
    if(check):
        return half1 + half2
 
    # If same unique element is not
    # present in S and P, then take
    # characters that make string T
    # lexicographically smallest
    for i in range(ord('a'), ord('z') + 1):
        if(mapS[i] > 0 or mapP[i] > 0):
            half1 += chr(i)
            return half1 + half2
 
    # If no unique element is
    # present in both string S and P
    return half1 + half2
 
# Driver Code
 
# Given string S and P
S = "aeabb"
P = "dfedf"
 
# Function call
print(mergePalindromes(S, P))
 
# This code is contributed by Shivam Singh


C#
// C# program for the above approach
using System;
using System.Collections.Generic;
using System.Text;
 
class GFG{
 
// Function to find largest palindrome
// possible from S and P after rearranging
// characters to make palindromic string T
static string mergePalindromes(string S,
                               string P)
{
 
    // Using unordered_map to store
    // frequency of elements mapT will
    // have freq of elements of T
    Dictionary mapS = new Dictionary();
    Dictionary mapP = new Dictionary();
    Dictionary mapT = new Dictionary();
 
    // Size of both the strings
    int n = S.Length, m = P.Length;
     
    for(char i = 'a'; i <= 'z'; i++)
    {
        mapS[i] = 0;
        mapP[i] = 0;
        mapT[i] = 0;
    }
     
    for(int i = 0; i < n; i++)
    {
        mapS[S[i]]++;
    }
     
    for(int i = 0; i < m; i++)
    {
        mapP[P[i]]++;
    }
 
    // Take all character in mapT which
    // occur even number of times in
    // respective strings & simultaneously
    // update number of characters left in map
    for(char i = 'a'; i <= 'z'; i++)
    {
        if (mapS[i] % 2 == 0)
        {
            mapT[i] += mapS[i];
            mapS[i] = 0;
        }
        else
        {
            mapT[i] += mapS[i] - 1;
            mapS[i] = 1;
        }
 
        if (mapP[i] % 2 == 0)
        {
            mapT[i] += mapP[i];
            mapP[i] = 0;
        }
        else
        {
            mapT[i] += mapP[i] - 1;
            mapP[i] = 1;
        }
    }
 
    // Check if a unique character is
    // present in both string S and P
    int check = 0;
 
    for(char i = 'a'; i <= 'z'; i++)
    {
        if (mapS[i] > 0 && mapP[i] > 0)
        {
            mapT[i] += 2;
            check = 1;
            break;
        }
    }
 
    // Making string T in two halves
    // half1 - first half
    // half2 - second half
    string half1 = "", half2 = "";
 
    for(char i = 'a'; i <= 'z'; i++)
    {
        for(int j = 0; (2 * j) < mapT[i]; j++)
        {
            half1 += i;
            half2 += i;
        }
    }
 
    // Reverse the half2 to attach with half1
    // to make palindrome T
    char[] tmp = half2.ToCharArray();
    Array.Reverse(tmp);
    half2 = new string(tmp);
 
    // If same unique element is present
    // in both S and P, then taking that only
    // which is already taken through mapT
    if (check != 0)
    {
        return half1 + half2;
    }
 
    // If same unique element is not
    // present in S and P, then take
    // characters that make string T
    // lexicographically smallest
    for(char i = 'a'; i <= 'z'; i++)
    {
        if (mapS[i] > 0 || mapP[i] > 0)
        {
            half1 += i;
            return half1 + half2;
        }
    }
 
    // If no unique element is
    // present in both string S and P
    return half1 + half2;
}
 
// Driver Code
public static void Main(string []args)
{
     
    // Given two strings S and P
    string S = "aeabb";
    string P = "dfedf";
     
    Console.Write(mergePalindromes(S, P));
}
}
 
// This code is contributed by rutvik_56


输出:
abdeffedba



时间复杂度: O(N),其中N是字符串S或P的长度。
辅助空间: O(N)