Short Palindrome Discussions | Algorithms | HackerRank

Short Palindrome

  • + 3 comments

    Building on @berke_evrensevdi and @igoryk's code + explanation, here is a brief explanation of why it works:

    Basically remember your palindrome can start and end from anywhere, which is what makes this challenge so challenging. Additonally the fact you need two nested palindromes means a brute force approach is O(n^2) and bound to fail the time limit.

    So instead what can you do?

    Well you can iterate over the string, and for every character occurrence you can note it down as a potential starting place for your outer palindrome. That is what dim1 is for.

    Consequently you can also have pairs of characters that are located at different indices like a,b at indices (i,j), where these don't necessarily have to be next to one another. Because each character can potentially be paired with another from the alphabet, this is why dim2 is 26x26. Additionally, if i represents the starting index of our outer palindrome, j is the starting index of our inner palindrome.

    So far we have been tracking two characters, but remember, we need 4 to make 2 nested palindromes. This is where dim3 comes in: it checks where we have a pair (i,j) like above such that the character at index j is repeated. In other words if we have the characters a,b if we see another b then we can increment that index at dim3. Since this is only keeping track of a closing inner palindrome, we only need 26 characters here.

    Finally, every time we encounter a new character, we check, do we have a triplet of 3 characters in dim3 that includes a closed palindrome? If so, then if our current character matches that first one, add it to our answer.

    Now all of these if...else statements are unnecessary because we use data structures that account for all of these possibilities, meaning if there are no matches then one of our arrays will just have 0 as an entry and that's it. What makes this difficult to grasp is that the code executes in reverse order from how I described it BECAUSE it takes in each character one at a time instead of being able to look ahead. Either way, I hope this explanation was useful, if you have any questions feel free to comment below.

    def shortPalindrome(s):
        # Write your code here
        # dim1[i] - number of times character i has been seen so far
        # dim2[i][j] - number of tuples of (i, j) characters seen so far
        # dim3[i] - number of tuples of (i,j,j) tuples seen so far
        dim1 = [0] * 26
        dim2 = [0] * 26 * 26
        dim3 = [0] * 26
        count = 0
        mod = 1000000007
        for k in s:
            c = ord(k) - ord('a')
            count = (count + dim3[c]) % mod
            ic = c
            for i in range(26):             
                dim3[i] = (dim3[i] + dim2[ic]) % mod      
                dim2[ic] = (dim2[ic] + dim1[i]) % mod
                ic += 26 
            dim1[c] += 1
        return count