-
Notifications
You must be signed in to change notification settings - Fork 622
/
Copy pathcreate_palindrom.py
132 lines (102 loc) · 3.85 KB
/
create_palindrom.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
'''
Create Palindrome (Minimum Insertions to Form a Palindrome)
Given a string, find the palindrome that can be made by inserting the fewest number of characters as possible anywhere in the word.
If there is more than one palindrome of minimum length that can be made, return the lexicographically earliest one (the first one alphabetically).
Input: 'race'
Output: 'ecarace'
Output explanation: Since we can add three letters to it (which is the smallest amount to make a palindrome).
There are seven other palindromes that can be made from "race" by adding three letters, but "ecarace" comes first alphabetically.
Input: 'google'
Output: 'elgoogle'
Input: 'abcda'
Output: 'adcbcda'
Output explanation: Number of insertions required is 2 - aDCbcda (between the first and second character).
Input: 'adefgfdcba'
Output: 'abcdefgfedcba'
Output explanation: Number of insertions required is 3 i.e. aBCdefgfEdcba.
=========================================
Recursive count how many insertions are needed, very slow and inefficient.
Time Complexity: O(2^N)
Space Complexity: O(N^2) , for each function call a new string is created (and the recursion can have depth of max N calls)
Dynamic programming. Count intersections looking in 3 direction in the dp table (diagonally left-up or min(left, up)).
Time Complexity: O(N^2)
Space Complexity: O(N^2)
'''
##############
# Solution 1 #
##############
def create_palindrome_1(word):
n = len(word)
# base cases
if n == 1:
return word
if n == 2:
if word[0] != word[1]:
word += word[0] # make a palindrom
return word
# check if the first and last chars are same
if word[0] == word[-1]:
# add first and last chars
return word[0] + create_palindrome_1(word[1:-1]) + word[-1]
# if not remove the first and after that the last char
# and find which result has less chars
first = create_palindrome_1(word[1:])
first = word[0] + first + word[0] # add first char twice
last = create_palindrome_1(word[:-1])
last = word[-1] + last + word[-1] # add last char twice
if len(first) < len(last):
return first
return last
##############
# Solution 2 #
##############
import math
def create_palindrome_2(word):
n = len(word)
dp = [[0 for j in range(n)] for i in range(n)]
# run dp
for gap in range(1, n):
left = 0
for right in range(gap, n):
if word[left] == word[right]:
dp[left][right] = dp[left + 1][right - 1]
else:
dp[left][right] = min(dp[left][right - 1], dp[left + 1][right]) + 1
left += 1
# build the palindrome using the dp table
return build_palindrome(word, dp, 0, n-1)
def build_palindrome(word, dp, left, right):
# similar like the first solution, but without exponentialy branching
# this is linear time, we already know the inserting values
if left > right:
return ''
if left == right:
return word[left]
if word[left] == word[right]:
return word[left] + build_palindrome(word, dp, left + 1, right - 1) + word[left]
if dp[left + 1][right] < dp[left][right - 1]:
return word[left] + build_palindrome(word, dp, left + 1, right) + word[left]
return word[right] + build_palindrome(word, dp, left, right - 1) + word[right]
###########
# Testing #
###########
# Test 1
# Correct result => 'ecarace'
word = 'race'
print(create_palindrome_1(word))
print(create_palindrome_2(word))
# Test 2
# Correct result => 'elgoogle'
word = 'google'
print(create_palindrome_1(word))
print(create_palindrome_2(word))
# Test 3
# Correct result => 'adcbcda'
word = 'abcda'
print(create_palindrome_1(word))
print(create_palindrome_2(word))
# Test 4
# Correct result => 'abcdefgfedcba'
word = 'adefgfdcba'
print(create_palindrome_1(word))
print(create_palindrome_2(word))