In this problem, you’re trying to minimize the number of substring queries. You can do this, in the average case, with memoization, compared to the brute-force search you are doing now.
However
The problem statement says that the answer must make no more than O(n log n) queries, and the algorithm below makes O(N²) queries in the worst case (when the string consists of a single repeated character).
You could enhance other algorithms with some form of memo-ization. Write a wrapper that maintains a lookup table indexed by (i,j), where j > i, storing true
/false
values. Whenever you make a query, check the table first, and if the result is not cached, add it. Call the provided query function only through this wrapper. This way, you can avoid making duplicate queries.
But Anyway
Let’s take as an example the string "abaabb"
. The six length-one substrings are trivially palindromic and do not need to be checked. There are five length-two substrings, of which (3,4) (aa
) and (5,6) (bb
) are palindromes. There are four length-three substrings, of which only (1,3) (aba
) is palindromic.
The rest of the way, we can use the queries we have already done to optimize.
From this point on, if we remember which smaller substrings are and are not palindromic, we can start optimizing to avoid unnecessary queries. A string can only be palindromic if its middle is, and if its leftmost segment and its rightmost segment both are or neither are. So, for example, abba
is palindromic (and neither ab
nor ba
are), and aaaa
is palindromic (and both its left half and right half are). But, if we already know that the left half of abaa
is not palindromic and the right half is palindromic, we do not need to query the full substring. We know it cannot be.
There are three length-four substrings. We know that a length-four substring can only be a palindrome if its middle is. This allows us to skip checking three of the four; only (2,5) (baab
) has a palindromic middle. We can additionally look up in our dynamic table whether the left half (2,3) and the right half (4,5) are. Neither are, so the test passes and we do need to query whether this substring is a palindrome, and we find it is. So we’ve saved three queries over the brute-force search.
There are two length-five substrings. Neither has a palindromic middle, so we can skip querying either one. We could also have eliminated (2,6) (baabb
) on the grounds that the leading ba
is not palindromic but the trailing bb
is.
Finally, there is the one length-six substring, consisting of the whole string. The middle segment (2,5) (baab
) is palindromic, so we need to test the left and right segments. The left half is palindromic and the right half is not, or alternatively the leftmost two characters are not and the rightmost two are. Either is enough to tell is that the string cannot be palindromic, so we do not need to test it.
A brute-force search would have needed to do 15 searches, which is 50% more than we need if we use dynamic programming.
So, a better algorithm for this (given the artificial limitation that we cannot see the string, only whether an arbitrary substring is palindromic) might work from smaller to longer substrings and, for each substring, look up the memo-ized results for the left, middle and right substrings (for each possible radius) and check whether the previous queries already rule out it being palindromic. Only if all the checks pass do we need to query the substring.
We are not being graded on the time it takes to do this (or it’s assumed to be much faster than asking the Oracle a question), only on the number of queries we make, so eliminating as many queries as we can counts as a win for this problem.