2

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.

learner
  • 6,062
  • 14
  • 79
  • 139
  • Isn't a palindrome just if a string reads the same backwards as forwards? Why are you counting re-arranging the letters as well? edit: nevermind, saw you edited the question. – Fly Jul 11 '19 at 12:35
  • 4
    **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. – nice_dev Jul 11 '19 at 12:36
  • @vivek_23, I have added the modified code in my edit section based on your suggestion. but still I see same timeout issues. I there anything I need to change here? I added all letters to map and then checking if map has how many odd letters are present. – learner Jul 11 '19 at 12:51
  • @learner can you share a link to the question? I am sure when you iterate over each string, you could just remove the previous character count and increase the current character count and check for palindrome-ness. – nice_dev Jul 11 '19 at 13:45
  • @learner I am presuming an 26 * O(n^2) = O(n^2) solution should get accepted. – nice_dev Jul 11 '19 at 13:46
  • @vivek_23, sorry I do not have the link for this. – learner Jul 11 '19 at 16:41
  • @learner Then it makes it tricky for me to find out the issue. By the way, did you try the advice and also what is the maximum length of the string given ? – nice_dev Jul 11 '19 at 18:05
  • @vivek_23, I added code under edit section based on your advice. The maximum length of input string is 1000 characters. – learner Jul 11 '19 at 20:01
  • @learner I meant the second advice. – nice_dev Jul 12 '19 at 07:38

2 Answers2

4

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?

Paweł Bęza
  • 1,375
  • 1
  • 13
  • 23
  • Sorry, I did not understand the hint. If `bba` is taken, it is palindrome if re-arranged to `bab`. Now if I take `bbac`, this is not a palindrome. Can you please explain more details what the hint is for? – learner Jul 11 '19 at 20:03
  • @learner Consider all substring from index 0 of word `aabb` so we have `a`, `aa`, `aab`, `aabb`. You are analyzing each case separately but it's not necessary, when you append new letter it is enough to update number of `oddChars` and decide whether it satisfies condition or not. Thanks to that it's possible to count all substrings with specific start index in `O(n)` not in `O(n^2)` (you don't have to generate all possible substrings and then analyze it separately). Therefore whole complexity is `O(n^2)` not `O(n^3)`. – Paweł Bęza Jul 11 '19 at 20:37
  • I have updated my code, the edit section has latest code, in latest code I am not using `isPalindrome` method so not using `oddChars` variable. So now, this hint is still applicable? Can you please check – learner Jul 11 '19 at 20:40
  • Yes it is still applicable. As I said when you have word `aabb`, you check separately whether `a`, `aa`, `aab`, `aabb` satisfies condition. You can do it in one loop, starting from 'a' it is satisfies conditions(1 odd char and odd length), 'aa' satisfies(1 even char and even length) etc. You can do it in one go for specific start index. – Paweł Bęza Jul 11 '19 at 20:44
  • So what I understand is `void subString(String input, List list)` here I am getting substrings, so here itself I need to find the evens and odd counts (as I did in my Edit section of code with HashMap) and decide whether it is a palindrome or not. Is that correct? – learner Jul 11 '19 at 20:50
  • Exactly, `i` is beginning and `j` is the end of you currently analyzed substring. And `j=i` at the beginning since single character character also should be taken into consideration. – Paweł Bęza Jul 11 '19 at 20:56
  • I am already considering single character as palindrome by setting my count of palidrome variable like this `int count = str.length();`. Is there anything else to improve? – learner Jul 11 '19 at 21:18
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/196345/discussion-between-pawel-beza-and-learner). – Paweł Bęza Jul 11 '19 at 21:19
0
  • 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"));
  }
}
nice_dev
  • 17,053
  • 2
  • 21
  • 35