Gaurav Gupta
Gaurav Gupta

Reputation: 99

Finding longest but lexicographically smallest palindrome in case of more than one palindromes

Given a string, I need to find the longest palindrome that can be constructed by removing or shuffling characters from the string. If more than one palindrome exists of same length then I need to make ensure that lexicographically smallest one is been given as output. Example : "adskassda" Output expected is : "adsasda"

I am able to find largest palindrome, but how to ensure in case of multiple of same maximum length lexicographically smallest one is been given as output ?

Any palindromic string can be divided into three parts – beg, mid and end. For palindromic string of odd length say 2n + 1, ‘beg’ consists of first n characters of the string, ‘mid’ will consist of only 1 character i.e. (n + 1)th character and ‘end’ will consists of last n characters of the palindromic string. For palindromic string of even length 2n, ‘mid’ will always be empty. It should be noted that ‘end’ will be reverse of ‘beg’ in order for string to be palindrome. I have used same logic for this too.

#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);
}

I am getting "adsssda" but expected is "adsasda"

Upvotes: 4

Views: 7093

Answers (3)

Sdembla
Sdembla

Reputation: 1707

I added a small change in the code - Sort lexicographically as soon as we get the left part. This may be required in Java. When I wrote the above code in java, I got "asdadsa" instead of "adsasda"

Here is the code in 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));
    }
}

There may be some refactoring required, example using existing lib in Java to add repeat characters in StringBuilder. But the above code provides the solution.

Upvotes: 0

Steve
Steve

Reputation: 1810

This seemed to work for me, although my testing was far from extensive:

#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;
}

Upvotes: 0

Ameer Jewdaki
Ameer Jewdaki

Reputation: 1798

You only have a simple error. When you want to chose the middle character, the first time you see one with and odd frequency, you should choose it and never update it again, because that'll be the one with the lowest lexicographical order. That's why I've added the boolean variable mid_char_chosen and once it's set to true it will not be updated again. There's another corner case you haven't considered: if all frequencies are even then there'll be no midle character and the result will have even number of characters. So the output should ommit middle character. With these minor modifications, I think the code runs:

#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;
}

Upvotes: 0

Related Questions