From 54006868aed54d462802aee332ce8a8a92322712 Mon Sep 17 00:00:00 2001 From: Ronny De Winter Date: Sun, 4 Oct 2020 23:05:26 +0200 Subject: [PATCH 1/6] improve maintainability index mi 55.888 -> 91.1844 --- strings/lower.py | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/strings/lower.py b/strings/lower.py index b7abe9fc957d..d2f509d7cddb 100644 --- a/strings/lower.py +++ b/strings/lower.py @@ -1,26 +1,30 @@ -def lower(word: str) -> str: +CAPITALS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + +def lower_char(capital: str) -> str: + """ + Convert a capital to a lowercase letter + """ + # int value of lowercase char = int value of uppercase char + 32 + return chr(ord(capital) + 32) + + +def lower(string: str) -> str: """ - Will convert the entire string to lowecase letters - - >>> lower("wow") - 'wow' - >>> lower("HellZo") - 'hellzo' - >>> lower("WHAT") - 'what' - >>> lower("wh[]32") - 'wh[]32' - >>> lower("whAT") - 'what' + Convert string to lowercase """ + return "".join(lower_char(char) if char in CAPITALS else char for char in string) + - # converting to ascii value int value and checking to see if char is a capital - # letter if it is a capital letter it is getting shift by 32 which makes it a lower - # case letter - return "".join(chr(ord(char) + 32) if "A" <= char <= "Z" else char for char in word) +import unittest +class TestLower(unittest.TestCase): -if __name__ == "__main__": - from doctest import testmod + def test_lower(self): + self.assertEqual(lower("wow"), "wow") + self.assertEqual(lower("HellZo"), "hellzo") + self.assertEqual(lower("WHAT"), "what") + self.assertEqual(lower("wh[]32"), "wh[]32") + self.assertEqual(lower("whAT"), "what") - testmod() +if __name__ == '__main__': + unittest.main() \ No newline at end of file From 43cc46f253258864e14654baaeb9af5f42094f46 Mon Sep 17 00:00:00 2001 From: Ronny De Winter Date: Sun, 4 Oct 2020 23:35:00 +0200 Subject: [PATCH 2/6] blank line at end of file --- strings/lower.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/strings/lower.py b/strings/lower.py index d2f509d7cddb..ab465591ce62 100644 --- a/strings/lower.py +++ b/strings/lower.py @@ -27,4 +27,5 @@ def test_lower(self): self.assertEqual(lower("whAT"), "what") if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() + \ No newline at end of file From 361e984201e682a3ecaa5b3218f958e2480ba495 Mon Sep 17 00:00:00 2001 From: Ronny De Winter Date: Sun, 4 Oct 2020 23:57:38 +0200 Subject: [PATCH 3/6] import at top --- strings/lower.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/strings/lower.py b/strings/lower.py index ab465591ce62..cfd93822becc 100644 --- a/strings/lower.py +++ b/strings/lower.py @@ -1,3 +1,5 @@ +import unittest + CAPITALS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' def lower_char(capital: str) -> str: @@ -15,8 +17,6 @@ def lower(string: str) -> str: return "".join(lower_char(char) if char in CAPITALS else char for char in string) -import unittest - class TestLower(unittest.TestCase): def test_lower(self): @@ -24,8 +24,7 @@ def test_lower(self): self.assertEqual(lower("HellZo"), "hellzo") self.assertEqual(lower("WHAT"), "what") self.assertEqual(lower("wh[]32"), "wh[]32") - self.assertEqual(lower("whAT"), "what") + self.assertEqual(lower("whAT"), "what") if __name__ == '__main__': - unittest.main() - \ No newline at end of file + unittest.main() \ No newline at end of file From 996ccb48d7dbab50b0edd705f40c0b4626b23094 Mon Sep 17 00:00:00 2001 From: Ronny De Winter Date: Mon, 5 Oct 2020 00:44:12 +0200 Subject: [PATCH 4/6] blacked --- strings/lower.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/strings/lower.py b/strings/lower.py index cfd93822becc..27e7c4837bde 100644 --- a/strings/lower.py +++ b/strings/lower.py @@ -1,6 +1,7 @@ import unittest -CAPITALS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +CAPITALS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + def lower_char(capital: str) -> str: """ @@ -18,13 +19,13 @@ def lower(string: str) -> str: class TestLower(unittest.TestCase): - def test_lower(self): self.assertEqual(lower("wow"), "wow") self.assertEqual(lower("HellZo"), "hellzo") self.assertEqual(lower("WHAT"), "what") self.assertEqual(lower("wh[]32"), "wh[]32") - self.assertEqual(lower("whAT"), "what") + self.assertEqual(lower("whAT"), "what") + -if __name__ == '__main__': - unittest.main() \ No newline at end of file +if __name__ == "__main__": + unittest.main() From 6676020042f499824dba8aaa28f0b65dcfa0d6c4 Mon Sep 17 00:00:00 2001 From: Ronny De Winter Date: Wed, 7 Oct 2020 17:39:47 +0200 Subject: [PATCH 5/6] bugfix: return '' for '' + maintainability edits --- strings/manacher.py | 118 +++++++++++++------------------------------- 1 file changed, 34 insertions(+), 84 deletions(-) diff --git a/strings/manacher.py b/strings/manacher.py index 73b31a7bea9f..42b4e6341ecd 100644 --- a/strings/manacher.py +++ b/strings/manacher.py @@ -1,107 +1,57 @@ -def palindromic_string(input_string): - """ - >>> palindromic_string('abbbaba') - 'abbba' - >>> palindromic_string('ababa') - 'ababa' - - Manacher’s algorithm which finds Longest palindromic Substring in linear time. +import unittest - 1. first this convert input_string("xyx") into new_string("x|y|x") where odd - positions are actual input characters. - 2. for each character in new_string it find corresponding length and store the - length and l,r to store previously calculated info.(please look the explanation - for details) - 3. return corresponding output_string by removing all "|" +def longest_palindromic_substring(string: str) -> str: """ - max_length = 0 - - # if input_string is "aba" than new_input_string become "a|b|a" - new_input_string = "" - output_string = "" - - # append each character + "|" in new_string for range(0, length-1) - for i in input_string[: len(input_string) - 1]: - new_input_string += i + "|" - # append last character - new_input_string += input_string[-1] + Manacher’s algorithm which finds Longest Palindromic Substring. + Source: https://en.wikipedia.org/wiki/Longest_palindromic_substring + """ + if string == "": + return "" - # we will store the starting and ending of previous furthest ending palindromic - # substring - l, r = 0, 0 + # create string with separators: "aba" -> "a|b|a" + new_string = "|".join(list(string)) + left = right = 0 # start/end index of longest palindrome so far # length[i] shows the length of palindromic substring with center i - length = [1 for i in range(len(new_input_string))] + length = [1] * len(new_string) + start = max_length = 0 - # for each character in new_string find corresponding palindromic string - for i in range(len(new_input_string)): - k = 1 if i > r else min(length[l + r - i] // 2, r - i + 1) + # for each character in new_string find the corresponding max palindrome length + # and store the length and left, right boundary + for i, _ in enumerate(new_string): + k = 1 if i > right else min(length[left + right - i] // 2, right - i + 1) while ( i - k >= 0 - and i + k < len(new_input_string) - and new_input_string[k + i] == new_input_string[i - k] + and i + k < len(new_string) + and new_string[k + i] == new_string[i - k] ): k += 1 length[i] = 2 * k - 1 - # does this string is ending after the previously explored end (that is r) ? - # if yes the update the new r to the last index of this - if i + k - 1 > r: - l = i - k + 1 # noqa: E741 - r = i + k - 1 + # update the right and left index if string ends after the previously right + if i + k - 1 > right: + left = i - k + 1 # noqa: E741 + right = i + k - 1 - # update max_length and start position if max_length < length[i]: max_length = length[i] start = i - # create that string - s = new_input_string[start - max_length // 2 : start + max_length // 2 + 1] - for i in s: - if i != "|": - output_string += i - - return output_string - + s = new_string[start - max_length // 2 : start + max_length // 2 + 1] + return "".join(s.split("|")) -if __name__ == "__main__": - import doctest - - doctest.testmod() - -""" -...a0...a1...a2.....a3......a4...a5...a6.... - -consider the string for which we are calculating the longest palindromic substring is -shown above where ... are some characters in between and right now we are calculating -the length of palindromic substring with center at a5 with following conditions : -i) we have stored the length of palindromic substring which has center at a3 (starts at - l ends at r) and it is the furthest ending till now, and it has ending after a6 -ii) a2 and a4 are equally distant from a3 so char(a2) == char(a4) -iii) a0 and a6 are equally distant from a3 so char(a0) == char(a6) -iv) a1 is corresponding equal character of a5 in palindrome with center a3 (remember - that in below derivation of a4==a6) -now for a5 we will calculate the length of palindromic substring with center as a5 but -can we use previously calculated information in some way? -Yes, look the above string we know that a5 is inside the palindrome with center a3 and -previously we have have calculated that -a0==a2 (palindrome of center a1) -a2==a4 (palindrome of center a3) -a0==a6 (palindrome of center a3) -so a4==a6 +class TestLongestPalindrome(unittest.TestCase): + def test_longest_palindromic_substring(self): + self.assertEqual(longest_palindromic_substring("abbbaba"), "abbba") + self.assertEqual(longest_palindromic_substring("ababa"), "ababa") + self.assertEqual(longest_palindromic_substring(""), "") + self.assertEqual(longest_palindromic_substring("a"), "a") + self.assertEqual(longest_palindromic_substring("aa"), "aa") + self.assertEqual(longest_palindromic_substring("abc"), "b") -so we can say that palindrome at center a5 is at least as long as palindrome at center -a1 but this only holds if a0 and a6 are inside the limits of palindrome centered at a3 -so finally .. -len_of_palindrome__at(a5) = min(len_of_palindrome_at(a1), r-a5) -where a3 lies from l to r and we have to keep updating that - -and if the a5 lies outside of l,r boundary we calculate length of palindrome with -bruteforce and update l,r. - -it gives the linear time complexity just like z-function -""" +if __name__ == "__main__": + unittest.main() From 1c0f1617206b7bab0ff7506217909c41e6a432e6 Mon Sep 17 00:00:00 2001 From: Ronny De Winter Date: Wed, 7 Oct 2020 17:58:09 +0200 Subject: [PATCH 6/6] trailing whitespace --- strings/manacher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/manacher.py b/strings/manacher.py index 42b4e6341ecd..305c9da7bf46 100644 --- a/strings/manacher.py +++ b/strings/manacher.py @@ -30,7 +30,7 @@ def longest_palindromic_substring(string: str) -> str: length[i] = 2 * k - 1 - # update the right and left index if string ends after the previously right + # update the right and left index if string ends after the previously right if i + k - 1 > right: left = i - k + 1 # noqa: E741 right = i + k - 1