【问题标题】:Finding longest but lexicographically smallest palindrome in case of more than one palindromes在多个回文的情况下找到最长但词典最小的回文
【发布时间】:2019-11-06 09:37:38
【问题描述】:

给定一个字符串,我需要找到可以通过从字符串中删除或改组字符来构造的最长回文。如果存在多个相同长度的回文,那么我需要确保以字典顺序最小的回文作为输出。 示例:“adskassda” 预期输出为:“adsasda”

我能够找到最大的回文,但是如何确保在多个相同的最大长度的情况下,按字典顺序最小的一个作为输出?

任何回文字符串都可以分为三个部分——beg、mid和end。对于奇数长度的回文字符串,比如 2n + 1,“beg”由字符串的前 n 个字符组成,“mid”将仅包含 1 个字符,即第 (n + 1) 个字符,“end”将由最后 n 个字符组成的回文字符串。对于偶数长度为 2n 的回文字符串,“mid”将始终为空。应该注意的是,“end”将与“beg”相反,以使字符串成为回文。 我也使用了相同的逻辑。

#include <bits/stdc++.h>
using namespace std;

string longestPalindrome(string str){
    map<char,int> frequencyChar;
    for(int i=0;i<str.length();i++){
        frequencyChar[str[i]]++;
    }
    char middle_character;
    string leftStr;
    for(auto it: frequencyChar){
        char currentChar=it.first;
        int frequencyCurrentChr = it.second;
        if(frequencyCurrentChr%2!=0){
            middle_character=currentChar;
        }
        leftStr.append(frequencyCurrentChr/2,currentChar);
    }
    string rightStr(leftStr.rbegin(),leftStr.rend());
    return leftStr + middle_character + rightStr;
}
int main() {
    string str = "adskassda";
    cout<<longestPalindrome(str);
}

我收到“adsssda”但预期是“adsasda”

【问题讨论】:

  • 当您确定middle_character 时,您可以/应该将std::min() 应用于之前的候选人和新候选人。此外,您应该初始化middle_character(例如'\0')以识别是否已经有候选人。如果找不到候选字(即所有字符的频率相同),这也很有用。
  • @Scheff 找到带有中间字符的最小值可能不适用于当前的代码方法。请参阅此参考:ideone.com/sCCdcm
  • 确实如此:Live Demo on coliru。 ;-)
  • 只是对风格的评论,除非您正在开发 libstdc++,否则您不应在 bits 子目录中包含 &lt;bits/stdc++.h&gt; 或其他任何内容。这些是库实现使用的内部文件,请改用标准定义的包含文件。
  • 请注意,我用 127 初始化了 middle_char,以消除在 min() 之前进行额外检查的需要。您没有进行额外检查,因此您最终将始终得到middle_char == 0。在return 之前,还需要检查以插入(或不插入)middle_char,前提是它不再存在初始化。价值。

标签: c++ algorithm palindrome


【解决方案1】:

你只有一个简单的错误。当您要选择中间字符时,当您第一次看到一个频率奇数的字符时,您应该选择它并且永远不要再更新它,因为那将是字典顺序最低的那个。这就是我添加布尔变量mid_char_chosen 的原因,一旦它设置为true,它将不会再次更新。还有一个你没有考虑过的极端情况:如果所有频率都是偶数,那么将没有中间字符,结果将有偶数个字符。所以输出应该省略中间字符。通过这些小的修改,我认为代码可以运行:

#include <bits/stdc++.h>
using namespace std;

string longestPalindrome(string str){
    map<char,int> frequencyChar;
    for(int i=0;i<str.length();i++){
        frequencyChar[str[i]]++;
    }
    char middle_character;
    string leftStr;
    bool mid_char_chosen = false;
    for(auto it: frequencyChar){
        char currentChar=it.first;
        int frequencyCurrentChr = it.second;
        if(!mid_char_chosen and frequencyCurrentChr%2!=0){
            middle_character=currentChar;
            mid_char_chosen = true;
        }
        leftStr.append(1*(frequencyCurrentChr/2),currentChar);
    }
    string rightStr(leftStr.rbegin(),leftStr.rend());
    if (mid_char_chosen)
        return leftStr + middle_character + rightStr;
    else
        return leftStr +  rightStr;
}
int main() {
    string str = "adskassda";
    cout<<longestPalindrome(str) << endl;
}

【讨论】:

    【解决方案2】:

    这似乎对我有用,尽管我的测试远非广泛:

    #include <iostream>
    #include <string>
    #include <map>
    #include <algorithm>
    using namespace std;
    
    int main()
    {
        string in("adskassda");
        map<char, int> chars;
        string out;
    
        for (auto c : in)
        {
            ++chars[c];
        }
    
        string middle;
        for (auto e : chars)
        {
            if (e.second >= 2)
            {
                out.append(e.second/2, e.first);
                e.second = e.second%2;
            }
    
            if (e.second && middle.empty())
                middle = e.first;
        }
    
        string tail(out);
        reverse(tail.begin(), tail.end());
        out = out + middle + tail;
    
        cout << in << endl;
        cout << out << endl;
    }
    

    【讨论】:

    • 这会返回最长的字典序最小的回文吗?
    • @0x499602D2:最长但字典最小是我的意图。正如我所说,我只是表面上测试了它。不过,逻辑对我来说似乎是合理的。
    【解决方案3】:

    我在代码中添加了一个小改动 - 一旦我们得到左侧部分,就按字典顺序排序。这在 Java 中可能是必需的。 当我用java编写上面的代码时,我得到的是“asdadsa”而不是“adsasda”

    这是Java代码:

    import java.util.*;
    
    public class Solution {
    
        public static String longPalindrome(String a) {
            Map<Character, Integer> map = new HashMap<>();
            for(int i=0; i<a.length(); i++) {
                map.put(a.charAt(i), map.getOrDefault(a.charAt(i), 0) + 1);
            }
            char mid = 0;
            boolean mid_chosen = false;
            StringBuilder left = new StringBuilder();
            for(Map.Entry<Character, Integer> entry : map.entrySet()) {
                if(!mid_chosen && entry.getValue() % 2 != 0) { //odd
                    mid_chosen = true;
                    mid = entry.getKey();
                }
                //Adding elements to left
                for(int k=0; k<entry.getValue()/2; k++) {
                    left.append(entry.getKey());
                }
            }
            //New Step added to sort it lexicographically 
            char[] leftChArr = left.toString().toCharArray();
            Arrays.sort(leftChArr);
            
            StringBuilder leftC = new StringBuilder(new String(leftChArr));
            StringBuilder right = new StringBuilder();
            //adding reverse elements to left
            for(int j=leftC.length()-1; j>=0; j--) {
                right.append(leftC.charAt(j));
            }
            if(mid_chosen == true) {
                leftC.append(mid).append(right);
            } else {
                leftC.append(right);
            }
            return leftC.toString();
        }
        
        public static void main(String[] args) {
            String str = "adskassda";
            System.out.println(longPalindrome(str));
        }
    }
    

    可能需要进行一些重构,例如使用 Java 中的现有库在 StringBuilder 中添加重复字符。但是上面的代码提供了解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多