# Python and Java problem solving: Longest palindrome substring

Posted by cstevio on Tue, 23 Jun 2020 11:31:42 +0200

Description:

Given a string s, find the longest palindrome substring in S. You can assume that the maximum length of S is 1000.

Example 1:

```//Type: "babad"

//Output: "bab"

//Note: "aba" is also a valid answer.

```

Example 2:

```//Input: "cbbd"

//Output: "bb"

```

Solutions to problems

Solution 1 - central expansion method

Because of the symmetry of palindrome string, one number can be selected as the center each time to expand left and right to determine whether it is a palindrome string.

Since strings can be odd or even, you need to start expanding between 1 or 2 characters.

i + i - 1 expansion center.

Then i is the odd digit,

i + 1 is even digit.

Based on this theory, each cycle can be extended to both sides.

The time complexity of this solution is O(n^2).

The spatial complexity is O(1).

Solution 2 - horse drawn car algorithm

The first contact with this algorithm, but the person who came up with this algorithm, is really awesome.

The horse drawn cart algorithm improves the time complexity to linear.

This algorithm initially traverses characters and inserts a special symbol on both sides of each character. To avoid crossing the boundary, special labels are added at the beginning and the end, for example:

aabbcbbaa -> ^#a#a#b#b#c#b#b#a#a#\$

Ensure that the current string must be an odd number.

Then expand left and right.

An array arr with the length of the original string is used to store the maximum number of center extensions.

(the subscript of each element of arr - arr[i]) / 2 is the subscript of the character of the original string.

If we set C as the center of the string and R as the length to the right of the string, then R = C + arr[i].

At this time, we can use the central expansion method to find.

We use j to represent the subscript corresponding to the i-th character and C.

But there are three situations that can lead to incorrect arr[j]

1. Length exceeds R
2. arr[j] to the left boundary of the original string
3. When i is R

So in the above three cases, we need to use the central expansion method to do boundary treatment.

JS version

```/**

* @param  {string}  str

* @param  {number}  left

* @param  {number}  right

* @return  {number}

*/

const  expandCenter = (str, left, right) => {

while (left >= 0 && right < str.length && str[left] === str[right]) {

left--

right++

}

return  str.slice(left + 1, right)

}

/**

* @param  {string}  s

* @return  {string}

*/

const  longestPalindrome1 = (s) => {

if (!s || !s.length) {

return  ''

}

let  result = ''

for (let  i = 0; i < s.length; i++) {

const  odd = expandCenter(s, i, i)

const  even = expandCenter(s, i, i + 1)

if (odd.length > result.length) {

result = odd

}

if (even.length > result.length) {

result = even

}

}

return  result

}

/**

* @param  {string}  s

* @return  {string}

*/

const  setTarget = (s) => {

if (!s) {

return  ''

}

if (s.length === 0) {

return  '^\$'

}

let  res = '^'

for (let  i = 0, len = s.length; i < len; ++i) {

res = res + '#' + s.charAt(i)

}

res += '#\$'

return  res

}

/**

* @param  {string}  s

* @return  {string}

*/

const  longestPalindrome2 = (s) => {

let  str = setTarget(s)

let  len = str.length

let  arr = new  Array(len)

let  C = 0  // The center of the largest palindrome substring on the right boundary

let  R = 0  // Right boundary of substring

for (let  i = 1; i < len - 1; ++i) {

let  j = 2 * C - i

if (R > i) {

arr[i] = Math.min(R - i, arr[j]) // Right boundary processing

} else {

arr[i] = 0

}

// In case of the above three special cases, the central expansion method is used

while (str[i + 1 + arr[i]] === str[i - 1 - arr[i]]) {

arr[i]++

}

// Determine whether the value of R needs to be updated

if (i + arr[i] + R) {

C = i

R = i + arr[i]

}

}

let  maxLen = 0  // Maximum length

let  index = 0  // Central subscript

for (let  i = 1; i < len - 1; ++i) {

if (arr[i] > maxLen) {

maxLen = arr[i]

index = i

}

}

let  start = (index - maxLen) / 2

return  s.substring(start, start + maxLen)

}

```

TS version

```/**

* @Solution 1

* @thinking

* Because of the symmetry of palindrome string, one number can be selected as the center each time to expand left and right to determine whether it is a palindrome string.

* Since strings can be odd or even, you need to start expanding between 1 or 2 characters.

* i + i - 1 expansion center.

* And i is an odd number

* i + 1 Even digit

* Based on this theory, each cycle can be extended to both sides.

*

* The time complexity of this method is O(n^2)

*/

/**

* @param  {string}  str

* @param  {number}  left

* @param  {number}  right

* @return  {number}

*/

const  expandCenter = (str: string, left: number, right: number): string  => {

while (left >= 0 && right < str.length && str[left] === str[right]) {

left--

right++

}

return  str.slice(left + 1, right)

}

/**

* @param  {string}  s

* @return  {string}

*/

const  longestPalindrome1 = (s: string): string  => {

if (!s || !s.length) {

return  ''

}

let  result: string = ''

for (let  i: number = 0; i < s.length; i++) {

const  odd: string = expandCenter(s, i, i)

const  even: string = expandCenter(s, i, i + 1)

if (odd.length > result.length) {

result = odd

}

if (even.length > result.length) {

result = even

}

}

return  result

}

const  setTarget = (s: string): string  => {

if (!s) {

return  ''

}

if (s.length === 0) {

return  '^\$'

}

let  res: string = '^'

for (let  i: number = 0, len = s.length; i < len; ++i) {

res = res + '#' + s.charAt(i)

}

res += '#\$'

return  res

}

const  longestPalindrome2 = (s: string): string  => {

let  str: string = setTarget(s)

let  len: number = str.length

let  arr: number[] = new  Array(len)

let  C: number = 0  // The center of the largest palindrome substring on the right boundary

let  R: number = 0  // Right boundary of substring

for (let  i: number = 1; i < len - 1; ++i) {

let  j: number = 2 * C - i

if (R > i) {

arr[i] = Math.min(R - i, arr[j]) // Right boundary processing

} else {

arr[i] = 0

}

// In case of the above three special cases, the central expansion method is used

while (str[i + 1 + arr[i]] == str[i - 1 - arr[i]]) {

arr[i]++

}

// Determine whether the value of R needs to be updated

if (i + arr[i] + R) {

C = i

R = i + arr[i]

}

}

let  maxLen: number = 0  // Maximum length

let  index: number = 0  // Central subscript

for (let  i: number = 1; i < len - 1; ++i) {

if (arr[i] > maxLen) {

maxLen = arr[i]

index = i

}

}

let  start: number = (index - maxLen) / 2

return  s.substring(start, start + maxLen)

}

```

PY version

```from typing import List

import math

def  expandCenter(s: str, left: int, right: int) -> str:

while left >= 0  and right < len(s) and s[left] == s[right]:

left -= 1

right += 1

return s[left + 1: right]

def  longestPalindrome1(s: str) -> str:

if  not(s) or  not(len(s)):

return  ''

result: str = ''

for i in  range(len(s)):

odd: str = expandCenter(s, i, i)

even: str = expandCenter(s, i, i + 1)

if  len(odd) > len(result):

result = odd

if  len(even) > len(result):

result = even

return result

def  setTarget(s: str) -> str:

if  not(s):

return  ''

if (len(s) == 0):

return  '^\$'

res: str = '^'

for i in  range(len(s)):

res += '#'

res += s[i]

res += '#\$'

return res

def  longestPalindrome2(s: str) -> str:

newStr: str = setTarget(s)

l: int = len(newStr)

arr = [0  for _ in  range(l)]

C: int = 0

R: int = 0

for i in  range(l - 1):

j: int = 2 * C - i

if R > i:

arr[i] = min(R - i, arr[j])

else:

arr[i] = 0

while newStr[i + 1 + arr[i]] == newStr[i - 1 - arr[i]]:

arr[i] += 1

if i + arr[i] + R:

C = i

R = i + arr[i]

maxLen: int = 0

idx: int = 0

for i in  range(1, l - 1):

if arr[i] > maxLen:

maxLen = int(arr[i])

idx = i

start: int = int((idx - maxLen) / 2)

return s[start:start + maxLen]```