C++ 通过重新排列子串的字符,最大化回文字符串的值
在这个问题中,我们需要通过重新排列给定字符串的任意子串的字符,找到最大的回文字符串。
我们将使用位掩码来解决最大回文子串问题。如果任何子串的位掩码为0,它包含所有字符,甚至多次出现。因此,我们可以使用该子串的字符生成一个回文字符串,并且我们需要找到其中的最大回文字符串。
问题陈述 - 我们已经给定一个包含N个数字字符的字符串。我们需要通过重新排列给定字符串的任意子串的字符,找到最大的回文字符串。
示例示例
输入
alpha = "81343451";
输出
4315134
说明 - 我们可以通过重新排列字符将’1343451’子串变为回文串。
输入
alpha = "12345";
输出
5
解释 - 我们可以通过任何子字符串生成的最长回文字符串长度为5。
输入
alpha = "65433456";
输出
"65433456";
方法一
在这种方法中,我们将使用位掩码。我们将有一个长度为10的二进制字符串,二进制字符串的每个字符表示数字0到9。如果二进制字符串中任何字符的值为’1’,则子字符串中存在奇数次数的相关数字。
如果位掩码仅包含1,我们可以通过重新排列其字符选择一个子字符串来形成回文子字符串,因为它只包含一个出现奇数次数的数字。
所以,我们将找到所有具有位掩码0或只包含一个’1’的字符串,使它们成为回文字符串,并对答案取最大值。
算法
步骤1 - 定义大小为1025(210 + 1)的列表来存储掩码索引,并将’bitMask’初始化为0。还要初始化答案为’0’以存储最大有效的回文字符串。
步骤2 - 开始遍历数字字符串。
步骤3 - 将1左移字符值,字符值可以是0到9之间的值,并将其与’bitMask’值进行XOR运算。
步骤4 - 如果’bitMask’为0,则子字符串包含所有字符的偶数频率。因此,执行maxValue()函数以通过重新排列子字符串的字符来获取最大的回文字符串。
步骤4.1 - 在maxValue()函数中,定义’freq’映射以存储子字符串的字符频率。
步骤4.2 - 初始化’ temp’和’ odd ‘为空字符串。
步骤4.3 - 从末尾开始遍历映射。如果字符的频率是奇数,则将字符存储在’odd’中。否则,将freq/2个字符追加到’temp’字符串中。
步骤4.4 - 取’temp’字符串的反转。
步骤4.5 - 返回追加’temp’、’odd’和反向字符串后的结果字符串。
步骤5 - 执行getMaximumString()函数以从答案和maxValue()函数返回的值中获取最大字符串。
步骤5.1 - 在getMaximumString()函数中返回最大长度的字符串。如果两个字符串都相同,则返回字典序最大的字符串。
步骤5.2 - 将最大字符串存储在’answer’中。
步骤6 - 我们需要单独切换所有位并获得最大答案。因此,从0到9的数字开始遍历。
步骤7 - 在循环中,将1左移位数,并将其与’bitMask’值进行XOR运算。
步骤 8 - 如果’newBitMask’等于0,则子字符串只包含一个具有奇数频率的字符。因此,我们可以重新排列子字符串以形成回文串。将最大子字符串存储在’answer’中。
步骤 9 - 如果’newBitMask’已经存在于’index’数组中,在索引[newBitMask] + 1到p索引之间取一个子字符串,形成最大的回文字符串,并将最大字符串存储在’answer’变量中。
步骤 10 - 如果’bitMask’不存在于’index’数组中,则将其值更新为’p’索引。
步骤 11 - 返回’answer’。
示例
#include <bits/stdc++.h>
using namespace std;
// Rearrange characters to get the largest string
string maxValue(string &str, int start, int end) {
map<char, int> freq;
// Count frequency of each digit
for (int p = start; p <= end; p++) {
freq[str[p]]++;
}
string temp = "", odd = "";
// Traverse map in reverse order
for (auto iter = freq.rbegin(); iter != freq.rend(); iter++) {
// Take 1 odd number
if (iter->second % 2 != 0) {
odd = iter->first;
} else {
temp += string(iter->second / 2, iter->first);
}
}
// Reverse temp string to append it after the odd character
string rev = temp;
reverse(rev.begin(), rev.end());
// Return the largest palindromic string
return temp + odd + rev;
}
// Get maximum string
string getMaximumString(string temp1, string temp2) {
if (temp1.size() > temp2.size())
return temp1;
if (temp2.size() > temp1.size())
return temp2;
if (temp1 > temp2) {
return temp1;
}
return temp2;
}
string getMaximumPalindrome(string α) {
vector<int> index(1025, -1);
int bitMask = 0, len = alpha.size();
string answer = "0";
// Iterate over the string
for (int p = 0; p < len; p++) {
// Toggle the bit corresponding to the digit in the bitMask
bitMask ^= (1 << (alpha[p] - '0'));
// When bitMask is 0, all characters appear an even number of times
if (bitMask == 0) {
// Get maximum palindromic string using characters from 0 to p
answer = getMaximumString(answer, maxValue(alpha, 0, p));
}
// Change all bits and get a maximum answer
for (int q = 0; q <= 9; q++) {
// Toggle the mask
int newbitMask = bitMask;
newbitMask ^= (1 << q);
// If all characters appear even a number of times
if (newbitMask == 0) {
answer = getMaximumString(answer, maxValue(alpha, 0, p));
}
// If the new mask has already visited
else if (index[newbitMask] != -1) {
answer = getMaximumString(answer, maxValue(alpha, index[newbitMask] + 1, p));
}
}
// Updated the visited index of the mask
if (index[bitMask] == -1) {
index[bitMask] = p;
}
}
return answer;
}
int main() {
string alpha = "81343451";
cout << "The maximum palindromic substring that we can create is "
<<getMaximumPalindrome(alpha);
return 0;
}
输出
The maximum palindromic substring that we can create is 4315134
时间复杂度 – 遍历字符串和构造最大回文子串的时间复杂度为O(N*N)。
空间复杂度 – 使用哈希表存储字符频率和答案中的最大字符串的空间复杂度为O(N)。
位运算是一种非常强大的技巧,可以使得解决方案更有效率。如果我们使用朴素的方法解决这个问题,找到所有子串需要O(NN)的时间,重排字符串的字符需要O(N)的时间。所以,我们将问题的时间复杂度从O(N3)降低到了O(NN)。