Learner
Learner

Reputation: 21445

Get all possible palindromes from a given string

A substring is a contiguous range of characters within a string.

Now I need to find out how many substring that can be re-arranged that can form a palindrome.

For example: For input - aabb

a
aa
aab (because after re-arranging it becomes aba)
aabb (because after re-arranging it becomes abba)
a
abb (because after re-arranging it becomes bab)
b
bb
b

So we have 9 substring palindromes.

Here is the code I tried:

public static int getPalindromeCount(String str) {
    // all single characters are treated as palindrome
    int count = str.length();

    // Get all sub strings
    List<String> subs = new ArrayList<>();
    subString(str, subs);

    for (String sub : subs) {
        String rev = new StringBuilder(sub).reverse().toString();

        if (rev.equals(sub)) {
            System.out.println(sub);
            count++;
        } else {
            boolean valid = isPalindrome(sub);
            System.out.println(sub + " : " + valid);
            if (valid) {
                count++;
            }
        }
    }
    return count;
}

// Check if substring can form a Palindrome
private static boolean isPalindrome(String input) {
    Set<Character> oddChars = new HashSet<>();

    for (char c : input.toCharArray()) {
        if (!oddChars.add(c)) {
            oddChars.remove(c);
        }
    }
    return oddChars.size() <= 1;
}

// Get all substrings
private static void subString(String input, List<String> list) {
    for (int i = 0; i < input.length(); i++) {
        for (int j = i + 2; j <= input.length(); j++) {
            list.add(input.substring(i, j));
        }
    }
}

The method isPalindrome part of logic I have took from this post Check if a permutation of a string can become a palindrome

This code is working fine, but it is failing with time out errors.

I am not sure what are the inputs for which this is failing as they are hidden in my hackerrank challenge.

Edit:

I have modified my getPalidromeCount method to check for how many odd number of letters are there in input to decide palindrome count.

This is based on comment on this post:

Hint: A palindrome consists of all letters of even count or all letters of even count with one letter of odd count(the middle character). Now, you could count possible palindromes easily. – vivek_23

public static int getPalindromeCount(String str) {
    List<Integer> list = new ArrayList<>(strToEvaluate.size());
    for (String str : strToEvaluate) {
        int count = str.length();

        List<String> subs = new ArrayList<>();
        subString(str, subs);
        for (String sub : subs) {
            Map<Character, Integer> map = new HashMap<>();
            for (int i = 0; i < sub.length(); i++) {
                char c = sub.charAt(i);
                map.put(c, map.getOrDefault(c, 0) + 1);
            }
            int odds = 0;
            for (char key : map.keySet()) {
                if (map.get(key) % 2 != 0) {
                    odds++;
                    if (odds > 1) {
                        break;
                    }
                }
            }
            if (odds <= 1) {
                System.out.println(sub);
                count++;
            }

            list.add(count);
        }
    }
    return list;
}

But still I am seeing timeout errors. I am not using the isPalindrome method in this logic.

Upvotes: 2

Views: 2600

Answers (2)

nice_dev
nice_dev

Reputation: 17835

  • My assumption is that string consists of lowercase letters. If not, you could increase the hash size in the below array to accommodate ASCII values or better use a map for UTF-8 characters.
  • Instead of collecting all substrings and then individually checking each one(which would take O(n2) space, you could just iterate over them along the way, increase the current character count and check for palindromeness as shown below.

Code:

 class Solution{
  public static long getPalindromeCount(String s) {
    long cnt = 0,len = s.length();    
    for(int i=0;i<len;++i){
       int[] hash = new int[26];
       cnt++; // since 1 character is palindrome anyway
       for(int j=i+1;j<len;++j){
          hash[s.charAt(j)-'a']++;
          if(palindromePossible(hash)) cnt++; 
       }
    }
    return cnt;
  }

  private static boolean palindromePossible(int[] hash){
    int odd_cnt = 0;
    for(int i=0;i<hash.length;++i){
      if(hash[i] % 2 != 0) odd_cnt++;
    }
    return odd_cnt < 2;
  }

  public static void main(String[] args){
    System.out.println(getPalindromeCount("aabb"));
  }
}

Upvotes: 0

Paweł Bęza
Paweł Bęza

Reputation: 1425

There are n(n+1)/2 possible substrings and for each substring you check whether it can be re-arranged so that it forms a palindrome in O(k) where k is length of given substring, let's think if it is necessary to parse each substring separately.

Hint:

Let's say you have substring from index p to k, what can you say about substring from index p to k + 1. Is it really necessary to parse this extended substring separately?

Upvotes: 4

Related Questions