Code formatting
Your code is hard to read. I've seen worse, but do
- indent consistently, including ...
- avoid multiple closing braces on the same line;
- insert blank lines in appropriate places, at least
- after the
package
line
- after the
import
s
- between methods (constructors);
- avoid excess blank lines
Convention
Package names should be all lowercase. Yours (Palindrome) has an initial capital letter.
Implementation / efficiency
You asked specifically about efficiency, and there are indeed several opportunities for improvement here
You store your palindrome substrings in a List
, and avoid duplicates by testing whether that List
already contains()
each candidate you discover. This part is O(n2) in the number of palindromic substrings. You could instead do it in O(n) and without requiring an explicit check if you used a HashSet
for palindrome storage, or in O(n log n) and without the explicit check if you used a TreeSet
.
Between HashSet
and TreeSet
, the latter also allows you to skip the subsequent sorting, but for large numbers of elements it may be cheaper to collect elements in a HashSet
and afterward dump them to a List
and sort.
The actual palindrome search uses an exceedingly naive -- but clear -- algorithm. For each length from 2 through the length of the string, you test each substring of that length by extracting it as a String
, computing its reverse, and comparing the two.
Note first how many redundant reverses you are performing. You need only reverse the whole string, once, to obtain the reverses of all substrings.
Note second how many redundant palindrome checks you are performing. Given any palindromic substring of length greater than 3, the string obtained by removing the first and last characters is also a palindromic substring. You don't need to find all those inner ones separately if you structure your search to find the palindromic strings centered at each position.
Note also that your approach creates and discards a rather large number of temporary strings. It does this mainly because it relies on String.equals()
to do its comparisons.
You could build a much more efficient approach by:
- dumping the input string to a
char[]
;
- creating a separate
char[]
of the reversed input string; based on those arrays,
- for each index strictly between 0 and the string length less one, finding and storing the odd-length palindromic substrings centered at that index (based on the forward and reverse arrays);
- for each index strictly between 0 and the string length less one, find and store the even-length palindromic substrings centered between that index and the previous (based on the forward and reverse arrays).
That's still O(n2) in the worst case, but it cuts out a lot of excess temporary objects (duplicate palindromes are now the main source of unwanted temporaries), and it avoids all the unneeded reversals.
Fine details
In main()
, there is no need to perform a null test on scan
before closing it because there is no way scan
can be null
at that point.
The bounds on the inner loop of subPal()
don't capture the true limits. This is evident from the fact that you compute k = i + j - 1
at the beginning of each iteration, and continue
if that is too large. That's actually bad two ways: not only is the loop's termination condition deceptive, but you perform a bunch of do-nothing iterations that you could easily avoid. That is, instead of this ...
for (int j = 0; j <= N; j++) {
int k = i + j - 1;
if (k >= N)
continue;
... it would be better to simply ...
for (int j = 0; i + j <= N; j++) {