Add longest palindrome code
This commit is contained in:
parent
0f145f99c4
commit
1ffa96dd77
90
dotfiles/lib/python/longest_palindrome.py
Executable file
90
dotfiles/lib/python/longest_palindrome.py
Executable file
@ -0,0 +1,90 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import sys
|
||||||
|
from cached_property import cached_property
|
||||||
|
|
||||||
|
|
||||||
|
class PalindromeSubstringFinder(object):
|
||||||
|
|
||||||
|
def __init__(self, input_string):
|
||||||
|
self.input_string = input_string
|
||||||
|
self.input_length = len(input_string)
|
||||||
|
self.position_count = (len(input_string) * 2) - 1
|
||||||
|
self._palindrome_lengths = [0] * self.position_count
|
||||||
|
self._total_comparisons = 0
|
||||||
|
self._max_palindrome_index = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def longest_palindrome(self):
|
||||||
|
index = self._max_palindrome_index // 2
|
||||||
|
half_length = self.longest_palindrome_length // 2
|
||||||
|
offset = self.longest_palindrome_length % 2
|
||||||
|
left_index = index - half_length + 1 - offset
|
||||||
|
right_index = index + half_length + 1
|
||||||
|
return self.input_string[left_index:right_index]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def longest_palindrome_length(self):
|
||||||
|
return self._palindrome_lengths[self._max_palindrome_index]
|
||||||
|
|
||||||
|
def print_current_state(self, position):
|
||||||
|
print ("".join(map(str, self._palindrome_lengths)))
|
||||||
|
print (" ".join(self.input_string))
|
||||||
|
print ("{0}^".format(" " * position))
|
||||||
|
|
||||||
|
def palindrome_lengths(self):
|
||||||
|
if self.input_string is None or self.input_length < 1:
|
||||||
|
return []
|
||||||
|
max_reach = -1
|
||||||
|
for position in range(self.position_count):
|
||||||
|
starting_offset = self._palindrome_lengths[position] // 2
|
||||||
|
index = position // 2
|
||||||
|
right_offset = position % 2
|
||||||
|
|
||||||
|
palindrome_length, max_index = self.get_length_from_indices(
|
||||||
|
index - starting_offset,
|
||||||
|
index + starting_offset + right_offset,
|
||||||
|
)
|
||||||
|
|
||||||
|
self._palindrome_lengths[position] = palindrome_length
|
||||||
|
|
||||||
|
if palindrome_length > self._palindrome_lengths[self._max_palindrome_index]:
|
||||||
|
self._max_palindrome_index = position
|
||||||
|
|
||||||
|
if max_reach < max_index:
|
||||||
|
max_reach = max_index
|
||||||
|
self.copy_palindrome_lengths(position, palindrome_length)
|
||||||
|
|
||||||
|
self.print_current_state(position)
|
||||||
|
|
||||||
|
return self._palindrome_lengths
|
||||||
|
|
||||||
|
def copy_palindrome_lengths(self, position, palindrome_length):
|
||||||
|
# b a a b a a b
|
||||||
|
# 1004007004001
|
||||||
|
for offset in range(1, palindrome_length - 1):
|
||||||
|
self._palindrome_lengths[position + offset] = (
|
||||||
|
min(
|
||||||
|
self._palindrome_lengths[position - offset],
|
||||||
|
palindrome_length - offset
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_length_from_indices(self, left_index, right_index):
|
||||||
|
while (left_index >= 0 and right_index < self.input_length and
|
||||||
|
self.input_string[left_index] == self.input_string[right_index]):
|
||||||
|
self._total_comparisons += 1
|
||||||
|
left_index -= 1
|
||||||
|
right_index += 1
|
||||||
|
self._total_comparisons += 1
|
||||||
|
# We'll always go one set of indices PAST the point that we should have,
|
||||||
|
# so right_index - left_index + 1 becomes the below:
|
||||||
|
return right_index - left_index - 1, right_index - 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
target = sys.argv[1]
|
||||||
|
finder = PalindromeSubstringFinder(target)
|
||||||
|
finder.palindrome_lengths()
|
||||||
|
print(finder._total_comparisons)
|
||||||
|
print(finder._max_palindrome_index)
|
||||||
|
print(finder.longest_palindrome)
|
Loading…
Reference in New Issue
Block a user