2

I've written a small PHP function to find a length of a longest palindromic substring of a string. To avoid many loops I've used a recursion.

The idea behind algorithm is, to loop through an array and for each center (including centers between characters and on a character), recursively check left and right caret values for equality. Iteration for a particular center ends when characters are not equal or one of the carets is out of the array (word) range.

Questions:

1) Could you please write a math calculations which should be used to explain time complexity of this algorithm? In my understanding its O(n^2), but I'm struggling to confirm that with a detailed calculations.

2) What do you think about this solution, any improvement suggestions (considering it was written in 45 mins just for practice)? Are there better approaches from the time complexity perspective?

To simplify the example I've dropped some input checks (more in comments).

Thanks guys, cheers.

<?php
/**
 * Find length of the longest palindromic substring of a string.
 *
 * O(n^2)
 * questions by developer
 * 1) Is the solution meant to be case sensitive? (no)
 * 2) Do phrase palindromes need to be taken into account? (no)
 * 3) What about punctuation? (no)
 */

$input = 'tttabcbarabb';
$input2 = 'taat';
$input3 = 'aaaaaa';
$input4 = 'ccc';
$input5 = 'bbbb';
$input6 = 'axvfdaaaaagdgre';
$input7 = 'adsasdabcgeeegcbgtrhtyjtj';

function getLenRecursive($l, $r, $word)
{
    if ($word === null || strlen($word) === 0) {
        return 0;
    }

    if ($l < 0 || !isset($word[$r]) || $word[$l] != $word[$r]) {
        $longest = ($r - 1) - ($l + 1) + 1;
        return !$longest ? 1 : $longest;
    }

    --$l;
    ++$r;

    return getLenRecursive($l, $r, $word);
}

function getLongestPalSubstrLength($inp)
{
    if ($inp === null || strlen($inp) === 0) {
        return 0;
    }

    $longestLength = 1;
    for ($i = 0; $i <= strlen($inp); $i++) {
        $l = $i - 1;
        $r = $i + 1;
        $length = getLenRecursive($l, $r, $inp); # around char
        if ($i > 0) {
            $length2 = getLenRecursive($l, $i, $inp); # around center
            $longerOne = $length > $length2 ? $length : $length2;
        } else {
            $longerOne = $length;
        }
        $longestLength = $longerOne > $longestLength ? $longerOne : $longestLength;
}

    return $longestLength;
}

echo 'expected: 5, got: ';
var_dump(getLongestPalSubstrLength($input));
echo 'expected: 4, got: ';
var_dump(getLongestPalSubstrLength($input2));
echo 'expected: 6, got: ';
var_dump(getLongestPalSubstrLength($input3));
echo 'expected: 3, got: ';
var_dump(getLongestPalSubstrLength($input4));
echo 'expected: 4, got: ';
var_dump(getLongestPalSubstrLength($input5));
echo 'expected: 5, got: ';
var_dump(getLongestPalSubstrLength($input6));
echo 'expected: 9, got: ';
var_dump(getLongestPalSubstrLength($input7));
Nik Denisov
  • 265
  • 1
  • 4
  • 16
  • You call `strlen()` n times in for loop. You should add a variable (e.g. `$strLen`) and hold that fixed length inside it. It doesn't change its big-O, but it's a performance improvement. – MAChitgarha Sep 11 '18 at 14:59

1 Answers1

2

Your code doesn't really need to be recursive. A simple while loop would do just fine. Yes, complexity is O(N^2). You have N options for selecting the middle point. The number of recursion steps goes from 1 to N/2. The sum of all that is 2 * (N/2) * (n/2 + 1) /2 and that is O(N^2).

For code review, I wouldn't do recursion here since it's fairly straightforward and you don't need the stack at all. I would replace it with a while loop (still in a separate function, to make the code more readable).

Sorin
  • 11,270
  • 17
  • 23