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