From 1282b9a08f15b3692ff35d1b988baf3a36f2b0b2 Mon Sep 17 00:00:00 2001 From: Pandiarajan S Date: Sun, 9 Jun 2024 14:12:49 +0530 Subject: [PATCH] first commit --- .gitignore | 2 + concepts/list_samples.py | 206 ++++++++++++++++++++++++++++++ concepts/strings_samples.py | 162 +++++++++++++++++++++++ helloworld.py | 1 + ik1_reverse_an_array.py | 64 ++++++++++ ik2_insert_an_element_at_a_pos.py | 60 +++++++++ ik3_intersection_of_array.py | 62 +++++++++ ik4_count_alphabets.py | 54 ++++++++ lc151_reverse_words_in_string.py | 124 ++++++++++++++++++ lc1_two_sum.py | 170 ++++++++++++++++++++++++ lc217_contains_duplicate.py | 123 ++++++++++++++++++ lc28_find_the_index_of.py | 118 +++++++++++++++++ lc349_intersection_of_arrays.py | 195 ++++++++++++++++++++++++++++ lc58_length_of_a_last_word.py | 99 ++++++++++++++ lc709_to_lowercase.py | 84 ++++++++++++ lc724_find_pivot_index.py | 110 ++++++++++++++++ lc7_reverse_an_integer.py | 138 ++++++++++++++++++++ requirements.txt | 55 ++++++++ 18 files changed, 1827 insertions(+) create mode 100644 .gitignore create mode 100644 concepts/list_samples.py create mode 100644 concepts/strings_samples.py create mode 100644 helloworld.py create mode 100644 ik1_reverse_an_array.py create mode 100644 ik2_insert_an_element_at_a_pos.py create mode 100644 ik3_intersection_of_array.py create mode 100644 ik4_count_alphabets.py create mode 100644 lc151_reverse_words_in_string.py create mode 100644 lc1_two_sum.py create mode 100644 lc217_contains_duplicate.py create mode 100644 lc28_find_the_index_of.py create mode 100644 lc349_intersection_of_arrays.py create mode 100644 lc58_length_of_a_last_word.py create mode 100644 lc709_to_lowercase.py create mode 100644 lc724_find_pivot_index.py create mode 100644 lc7_reverse_an_integer.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3214958 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.DS_Store +/.venv \ No newline at end of file diff --git a/concepts/list_samples.py b/concepts/list_samples.py new file mode 100644 index 0000000..5de2e5e --- /dev/null +++ b/concepts/list_samples.py @@ -0,0 +1,206 @@ +# Simple list examples +def print_items_in_list(): + numbers = [1, 2, 3, 4, 5] + for num in numbers: + print(num, end=" ") + +############ + +# https://www.programiz.com/python-programming/methods/list + +numbers = [21, 10, 54, 12] + +print("Before Append:", numbers) + +# using append method +numbers.append(32) +numbers.append(9) +print("After Append:", numbers) + +prime_numbers = [2, 3, 5] +print("List1:", prime_numbers) + +even_numbers = [4, 6, 8] +print("List2:", even_numbers) + +prime_numbers.extend(even_numbers) # list1.extends(list2) + +print("List after append:", prime_numbers) + +languages = ['Python', 'Swift', 'C++'] + +languages[2] = 'C' + +print(languages) # ['Python', 'Swift', 'C'] + +# insert method +vowel = ['a', 'e', 'i', 'u'] + +# 'o' is inserted at index 3 (4th position) +vowel.insert(3, 'o') + +print('List:', vowel) + +############## + + +animals = ['cat', 'dog', 'guinea pig', 'dog'] +animals.remove('dog') + +print('Updated animals list: ', animals) + +# error +#animals.remove('fish') + +# Updated animals List +print('Updated animals list: ', animals) + +# pop +languages = ['Python', 'Java', 'C++', 'French', 'C'] + +return_value = languages.pop(3) + +print('Return Value:', return_value) + +print('Updated List:', languages) + +languages.pop() +print(languages) + +# del + +my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9] + +# deleting the third item +del my_list[2] + +# Output: [1, 2, 4, 5, 6, 7, 8, 9] +print(my_list) + +# deleting items from 2nd to 4th +del my_list[1:4] + +# Output: [1, 6, 7, 8, 9] +print(my_list) + +# deleting all elements +del my_list[:] + +# Output: [] +print(my_list) + +prime_numbers = [2, 3, 5, 7, 9, 11] + +# remove all elements +prime_numbers.clear() + +# Updated prime_numbers List +print('List after clear():', prime_numbers) + + +# Output: List after clear(): [] + +############## + +# create a list +numbers = [2, 3, 5, 2, 11, 2, 7] + +count = numbers.count(2) + +print('Count of 2:', count) + +prime_numbers = [2, 3, 5, 7] + +prime_numbers.reverse() + +print('Reversed List:', prime_numbers) + +prime_numbers = [11, 3, 7, 5, 2] + +# sorting the list in ascending order +prime_numbers.sort() + +print(prime_numbers) + +vowels = ['e', 'a', 'u', 'o', 'i'] + +vowels.sort(reverse=True) +print('Sorted list (in Descending):', vowels) + +######### + +# https://www.programiz.com/python-programming/examples/list-slicing + +Lst = [50, 70, 30, 20, 90, 10, 50] + +# Display list +print(Lst[1:5]) # from index 1 till index 4 + +# Initialize list +List = [1, 2, 3, 4, 5, 6, 7, 8, 9] + +# Show original list +print("\nOriginal List:\n", List) + +print("\nSliced Lists: ") + +# Display sliced list +print(List[3:9:2]) + +# Display sliced list +print(List[::2]) + +print(List[::]) + +# String slicing +String = 'CodingIsFun' + +# Using indexing sequence +print(String[1:5]) + + +######### + + +# input values to list +list1 = [12, 3, 4, 15, 20] + +for elem in list1: + print(elem) + +list1.sort() + +print(list1) + +colors = ["Red", "Black", "Pink", "White"] + +colors.append("Blue") # add --> insert +colors.append("Orange") + +for color in colors: + print(color) + + +print(len(colors)) + +for i in range(len(colors)): + print(colors[i]) + +if "Grey" in colors: + print("Yes, present") + + +list2 = [] + +list2.append("Abc"); + +print(list2) + +####### + + + + + + + diff --git a/concepts/strings_samples.py b/concepts/strings_samples.py new file mode 100644 index 0000000..d99589c --- /dev/null +++ b/concepts/strings_samples.py @@ -0,0 +1,162 @@ +# This file contains all the samples for strings related usecase + + +# partition the string +# the below returns a tuple with "best" " " "technical interview prep course" + +input_words = "best technical interview prep course" +print(input_words.partition(" ")) +############################################################## + +str = "abcdac" + +substr = "xda" + +print(str.find(substr)) # + + + +# .join() with lists +numList = ['1', '2', '3', '4'] + +print(' | '.join(numList)) # "1 | 2 | 3, 4" + + +cars = "BMW-Telsa-Range Rover" + +# split at '-' +print(cars.split("-")) + + +words = "cats dogs lions" +print(words.split()) + +################# +# https://www.programiz.com/python-programming/methods/string +# https://www.programiz.com/python-programming/methods/string/split + +text = 'bat ball' + +print(len(text)) + +# replace 'ba' with 'ro' +replaced_text = text.replace('ba', 'ro') +print(replaced_text) + +song = 'Let it be, let it be, let it be, let it be' + +# replacing only two occurrences of 'let' +print(song.replace('let', "don't let", 2)) + +message = 'python is popular programming language' + +# number of occurrence of 'p' +print('Number of occurrence of p:', message.count('p')) + +# Output: Number of occurrence of p: 4 + +quote = 'Let it be, let it be, let it be' + +# first occurance of 'let it'(case sensitive) +result = quote.find('let it') +print("Substring 'let it':", result) + +# find returns -1 if substring not found +result = quote.find('small') +print("Substring 'small ':", result) + +# How to use find() +if (quote.find('be,') != -1): + print("Contains substring 'be,'") +else: + print("Doesn't contain substring") + + + +quote = 'Do small things with great love' + +# Substring is searched in 'hings with great love' +print(quote.find('small things', 10)) + +# Substring is searched in ' small things with great love' +print(quote.find('small things', 2)) + +# Substring is searched in 'hings with great lov' +print(quote.find('o small ', 10, -1)) + +# Substring is searched in 'll things with' +print(quote.find('things ', 6, 20)) + +#### + +# .join() with lists +numList = ['1', '2', '3', '4'] +separator = ', ' +print(' | '.join(numList)) # "1 | 2 | 3, 4" + +# .join() with tuples +numTuple = ('1', '2', '3', '4') +print(separator.join(numTuple)) + +s1 = 'abc' +s2 = '123' + +# each element of s2 is separated by s1 +# '1'+ 'abc'+ '2'+ 'abc'+ '3' +print('s1.join(s2):', s1.join(s2)) + +# each element of s1 is separated by s2 +# 'a'+ '123'+ 'b'+ '123'+ 'b' +print('s2.join(s1):', s2.join(s1)) + +# first string +firstString = "PYTHON IS AWESOME!" + +# second string +secondString = "PyThOn Is AwEsOmE!" + +if(firstString.lower() == secondString.lower()): + print("The strings are same.") +else: + print("The strings are not same.") + +sentence = "i love PYTHON" + +# converts first character to uppercase and others to lowercase +capitalized_string = sentence.capitalize() + +print(capitalized_string) + +# Output: I love python + + +message = 'Python is fun' + +print(message.startswith('Python')) + + +####### + +message = 'Python is fun' + +print(message.startswith('Python')) + +cars = 'BMW-Telsa-Range Rover' + +# split at '-' +print(cars.split('-')) + +text= 'Love thy neighbor' + +# splits at space +print(text.split()) + +grocery = 'Milk, Chicken, Bread' + +# splits at ',' +print(grocery.split(', ')) + +# Splits at ':' +print(grocery.split(':')) + +###### diff --git a/helloworld.py b/helloworld.py new file mode 100644 index 0000000..e75154b --- /dev/null +++ b/helloworld.py @@ -0,0 +1 @@ +print("hello world") \ No newline at end of file diff --git a/ik1_reverse_an_array.py b/ik1_reverse_an_array.py new file mode 100644 index 0000000..f30ac4b --- /dev/null +++ b/ik1_reverse_an_array.py @@ -0,0 +1,64 @@ +""" +Reverse An Array +Reverse a given list of numbers. + +Example One +input: [50, 35, 78, 66, 17] +Output: [17, 66, 78, 35, 50] + +Example Two +input: [50, 40, 30, 20] +Output: [20, 30, 40, 50] + +Notes +===== +Modify the input array in-place and return the modified array. +Constraints: + +1 <= size of the input array <= 106 +0 <= any element of the input array <= 106 +""" + +import unittest + +def reverse_array(nums: list[int]) -> list[int]: + """ + Args: + nums(list_int32) + Returns: + list_int32 + """ + # Option #1 + # One line built in solution + # nums.reverse() + + # Option #2 + # Using slicing + # nums = nums[::-1] + + # Option #3 + # Using default brute force technique with for + # result = [] + # for index in range(len(nums)-1, -1, -1): + # result.append(nums[index]) + # nums = result + + # Optoin #4 + # Using for loop but with reversed index + # nums = [num for num in reversed(nums)] + nums = [reversed(nums)] + + return nums + +class TestReverseArray(unittest.TestCase): + """Tesing Reverse array method implementation""" + def test_reverse_array(self): + """Test reverse array method implementatio both positive and negative cases""" + self.assertEqual(reverse_array([50, 40, 30, 20]), [20, 30, 40, 50]) + self.assertListEqual(reverse_array([50, 35, 78, 66, 17]), [17, 66, 78, 35, 50]) + self.assertListEqual(reverse_array([11]), [11]) + self.assertListEqual(reverse_array([]), []) + + +if __name__ == "__main__": + unittest.main() diff --git a/ik2_insert_an_element_at_a_pos.py b/ik2_insert_an_element_at_a_pos.py new file mode 100644 index 0000000..cc27bb0 --- /dev/null +++ b/ik2_insert_an_element_at_a_pos.py @@ -0,0 +1,60 @@ +""" +Insert An Element At A Specific Position In An Array +Given an array of numbers, insert a given element at the specified position in the array. + +Example One +input: +{ +"nums": [2, 4, 5, 6, -1], +"element": 3, +"position": 2 +} +Output: +[2, 3, 4, 5, 6] + +Example Two +input: +{ +"nums": [70, 60, 50, -1], +"element": 40, +"position": 4 +} +Output: +[70, 60, 50, 40] + + +Notes +===== +The last element of the array is -1 indicating a blank position. +The given position follows 1-based indexing. +Return the modified array. +Constraints: + +2 <= size of the input array <= 106 +0 <= elements of the array <= 106 +1 <= position <= size of the input array +""" + +import unittest + +def insert_an_element_at_an_array_position(nums:list[int], pos:int, element:int) -> list[int]: + """Insert an element at a given position in an array""" + nums.insert(pos-1, element) + nums.pop() + return nums + +class TestInsertAnElementAtAnArrayPosition(unittest.TestCase): + """Test class for a method that insert an element at a given position in an array""" + def test_insert_an_array_position(self) -> None: + """Test class for a method that insert an element at a given position in an array""" + self.assertEqual( + insert_an_element_at_an_array_position( + [2, 4, 5, 6, -1], 2, 3), [2, 3, 4, 5, 6] + ) + self.assertEqual( + insert_an_element_at_an_array_position( + [70, 60, 50, -1], 4, 40), [70, 60, 50, 40] + ) + +if __name__ == "__main__": + unittest.main() diff --git a/ik3_intersection_of_array.py b/ik3_intersection_of_array.py new file mode 100644 index 0000000..0c12102 --- /dev/null +++ b/ik3_intersection_of_array.py @@ -0,0 +1,62 @@ +""" +Intersection Of Two Arrays +Given two lists of numbers, find their intersection. + +Example One +{ +"a": [4, 2, 2, 3, 1], +"b": [2, 2, 2, 3, 3] +} +Output: +[2, 2, 3] + +Example Two +{ +"a": [6, 2, 4], +"b": [1, 5, 3, 7] +} +Output: +[] +Notes + +The order of elements in the output list does not matter. +The frequency of any number in the intersection + must be equal to the minimum of the frequency of that number in both the given lists. + +Constraints: + 1 <= size of the input lists <= 105 + -106 <= any element of the input lists <= 106 +""" +import unittest + +def intersection_of_arrays(nums1: list[int], nums2: list[int]) -> list[int]: + """ + By list comprehension + """ + result = [] + for x in nums1: + if (x not in result) and (x in nums2): + x_count_in_nums1 = nums1.count(x) + x_count_in_nums2 = nums2.count(x) + times = min(x_count_in_nums1, x_count_in_nums2) + result.extend([x] * times) + return result + + +class TestIntersectionOfArrays(unittest.TestCase): + """ + Test class + """ + def test_intersection_of_arrays(self) -> None: + """ + intersection_of_arrays_by_list_comprehension + """ + self.assertEqual(intersection_of_arrays( + [4, 2, 2, 3, 1],[2, 2, 2, 3, 3]), [2, 2, 3] + ) + self.assertEqual(intersection_of_arrays( + [6, 2, 4],[1, 5, 3, 7]), [] + ) + +if __name__ == "__main__": + unittest.main() diff --git a/ik4_count_alphabets.py b/ik4_count_alphabets.py new file mode 100644 index 0000000..eac5c59 --- /dev/null +++ b/ik4_count_alphabets.py @@ -0,0 +1,54 @@ +""" +Count Alphabets + +Count the number of alphabets in a given string. + +Example One +{ +"s": "#aBdj12C" +} +Output: +5 + + +Example Two +{ +"s": "123 !@#$" +} +Output: +0 + +Notes + +Constraints: +0 <= length of string <= 104 +String contains lower case and upper case English alphabets, + digits, and some special characters('!', '@', '#', '$', '*', ' ') only. +""" + +import unittest + +def count_alphabets(sentense: str) -> int: + """ + Count Alphabets + """ + alpha_chars = list(filter(lambda ch: ch.isalpha(), sentense)) + return len(alpha_chars) + + +class TestCountAlphabets(unittest.TestCase): + """ + Test count alphabets algorithm + """ + def test_count_alphabets(self) -> None: + """ + Default implementation using isalpha + """ + self.assertEqual(count_alphabets("#aBdj12C"), 5) + self.assertEqual(count_alphabets("123 !@#$"), 0) + self.assertEqual(count_alphabets(" "), 0) + self.assertEqual(count_alphabets("Ran 3 tests in 0.000s"), 11) + + +if __name__ == "__main__": + unittest.main() diff --git a/lc151_reverse_words_in_string.py b/lc151_reverse_words_in_string.py new file mode 100644 index 0000000..55bb663 --- /dev/null +++ b/lc151_reverse_words_in_string.py @@ -0,0 +1,124 @@ +""" +Given an input string s, reverse the order of the words. + +A word is defined as a sequence of non-space characters. +The words in s will be separated by at least one space. + +Return a string of the words in reverse order concatenated by a single space. +Note that s may contain leading or trailing spaces or multiple spaces between two words. +The returned string should only have a single space separating the words. +Do not include any extra spaces. + + +Example 1: +Input: s = "the sky is blue" +Output: "blue is sky the" + +Example 2: +Input: s = " hello world " +Output: "world hello" +Explanation: Your reversed string should not contain leading or trailing spaces. + +Example 3: +Input: s = "a good example" +Output: "example good a" +Explanation: You need to reduce multiple spaces between + words to a single space in the reversed string. + + +Constraints: + +1 <= s.length <= 104 +s contains English letters (upper-case and lower-case), digits, and spaces ' '. +There is at least one word in s. + + +Follow-up: If the string data type is mutable in your language, + can you solve it in-place with O(1) extra space? +""" + +import unittest + +def reverse_words_in_string(sentense: str) -> str: + """ + Reverse the word of the string in pythonic way + Time Complexity: O(n), + where n is the length of the input string. + This is because the function iterates through the string + once to split it into words and then again to reverse the list of words. + Space complexity: O(n), + where n is the length of the input string. + This is because the function creates a new list of words, + which can be up to n characters long. + """ + sentense = sentense.strip() + word_list = [word for word in sentense.split(" ") if len(word.strip()) > 0] + return " ".join(reversed(word_list)) + +def reverse_words_in_string_using_dequeue(sentense: str) -> str: + """ + Reverse the word of using dequeue + Time Complexity: O(n), + where n is the length of the input string. + This is because the function iterates through + the string once to split it into words and then again to reverse the list of words. + Space Complexity: O(n), + where n is the length of the input string. + This is because the function creates a new list of words, + which can be up to n characters long + """ + sentense = sentense.strip() + dequeue = list() + search_start = sentense.find(" ", 0, len(sentense) - 1) + prev_search_end = 0 + while search_start != -1: + item = sentense[prev_search_end:search_start].strip() + if len(item) > 0: + dequeue.insert(0, item) + prev_search_end = search_start + 1 + search_start = sentense.find(" ", prev_search_end, len(sentense) - 1) + + last_word = sentense[prev_search_end:len(sentense)].strip() + if len(last_word) > 0: + dequeue.insert(0, last_word) + + return " ".join(dequeue) + + + +class TestReverseWordInAString(unittest.TestCase): + """ + Unit test for Test ReveseWord in a string + """ + def test_reverse_word_in_string(self) -> None: + """ + test method test_reverse_word_in_string + """ + self.assertEqual(reverse_words_in_string("the sky is blue"), "blue is sky the") + self.assertEqual(reverse_words_in_string(" hello world "), "world hello") + self.assertEqual(reverse_words_in_string("a good example"), "example good a") + self.assertEqual(reverse_words_in_string("hi"), "hi") + self.assertEqual(reverse_words_in_string(" "), "") + self.assertEqual(reverse_words_in_string(" "), "") + + + def test_reverse_words_in_string_using_dequeue(self) -> None: + """ + test method test_reverse_word_in_string + """ + self.assertEqual( + reverse_words_in_string_using_dequeue("the sky is blue"), "blue is sky the" + ) + self.assertEqual( + reverse_words_in_string_using_dequeue(" hello world "), "world hello" + ) + self.assertEqual( + reverse_words_in_string_using_dequeue("a good example"), "example good a" + ) + self.assertEqual(reverse_words_in_string_using_dequeue("hi"), "hi") + self.assertEqual(reverse_words_in_string_using_dequeue(" "), "") + self.assertEqual(reverse_words_in_string_using_dequeue(" "), "") + + +if __name__ == "__main__": + unittest.main() diff --git a/lc1_two_sum.py b/lc1_two_sum.py new file mode 100644 index 0000000..6b52176 --- /dev/null +++ b/lc1_two_sum.py @@ -0,0 +1,170 @@ +""" +Given an array of integers nums and an integer target, +return indices of the two numbers such that they add up to target. + +You may assume that each input would have exactly one solution, +and you may not use the same element twice. + +You can return the answer in any order. + +Example 1: + +Input: nums = [2,7,11,15], target = 9 +Output: [0,1] +Explanation: Because nums[0] + nums[1] == 9, we return [0, 1]. +Example 2: + +Input: nums = [3,2,4], target = 6 +Output: [1,2] +Example 3: + +Input: nums = [3,3], target = 6 +Output: [0,1] + +""" + +import unittest + + +def two_sum_brute_force(nums: list[int], target: int) -> tuple[int, int]: + """ + Returns the indices of two numbers in the list that sum up to the target. + + This function takes in a list of integers `nums` and an integer `target`, + and returns a tuple of two indices `i` and `j` such that `nums[i] + nums[j] == target`. + If no such indices exist, it returns `-1, -1`. + + Algorithm Used: Brute Force + Time Complexity: O(n^2) + because it needs to traverse each element of the list nums twice + Space Complexity: O(1) + because it only uses a constant amount of space to store the indices i and j + and the temporary variables i_num and j_num. + """ + for i, i_num in enumerate(nums): + for j, j_num in enumerate(nums[i+1:], start=i+1): + if i_num + j_num == target: + return i, j + return -1, -1 + + +def two_sum_using_two_pointers(nums: list[int], target: int) -> tuple[int, int]: + """Two sum using two pointers + Algorithm Used: Two Pointers + Time Complexity: O(n) + because it needs to traverse the list only once + Space Complexity: O(1) + because it only uses a constant amount of space to store the indices i and j + """ + # Sort the number before proceed with the two pointers algorithm + nums.sort() + + left, right = 0, len(nums) - 1 + while left < right: + if nums[left] + nums[right] > target: + right -= 1 + elif nums[left] + nums[right] < target: + left += 1 + else: + return left, right + return -1, -1 + + +class TestTwoSumBruteForce(unittest.TestCase): + """ + Test case for the `two sum` problem. + This test case verifies the behavior of the `two sum` problem + by checking the correctness of its output for various input scenarios. + + The function takes in a list of integers `nums` and a target integer `target`, + and returns a tuple of two indices `i` and `j` such that `nums[i] + nums[j] == target`. + If no such indices exist, it returns `-1, -1`. + + The test cases cover the following scenarios: + + 1. Test case 1: Two unique indices with a valid sum. + - Input: `nums = [2, 7, 11, 15]`, `target = 9` + - Expected output: `(0, 1)` + + 2. Test case 2: Two unique indices with an invalid sum. + - Input: `nums = [2, 7, 11, 15]`, `target = 17` + - Expected output: `(-1, -1)` + + 3. Test case 3: No indices with a valid sum. + - Input: `nums = [2, 7, 11, 15]`, `target = 30` + - Expected output: `(-1, -1)` + + 4. Test case 4: Empty list. + - Input: `nums = []`, `target = 9` + - Expected output: `(-1, -1)` + + 5. Test case 5: Single element list. + - Input: `nums = [5]`, `target = 10` + - Expected output: `(-1, -1)` + + 6. Test case 6: List with duplicate elements. + - Input: `nums = [2, 7, 11, 11, 15]`, `target = 16` + - Expected output: `(1, 4)` + + 7. Test case 7: List with negative numbers. + - Input: `nums = [-1, 0, 1, 2, 3]`, `target = 0` + - Expected output: `(0, 4)` + """ + + def test_two_sum_brute_force(self) -> None: + """ + This test case is part of the unit tests for the `two_sum_brute_force` function. + """ + # Test case 1: Two unique indices with a valid sum + self.assertTupleEqual(two_sum_brute_force([2, 7, 11, 15], 9), (0, 1)) + + # Test case 2: Two unique indices with an invalid sum + self.assertTupleEqual(two_sum_brute_force([2, 7, 11, 15], 17), (0, 3)) + + # Test case 3: No indices with a valid sum + self.assertTupleEqual(two_sum_brute_force( + [2, 7, 11, 15], 30), (-1, -1)) + + # Test case 4: Empty list + self.assertTupleEqual(two_sum_brute_force([], 9), (-1, -1)) + + # Test case 5: Single element list + self.assertTupleEqual(two_sum_brute_force([5], 10), (-1, -1)) + + # Test case 6: List with duplicate elements + self.assertTupleEqual(two_sum_brute_force( + [2, 7, 11, 11, 15], 16), (-1, -1)) + + # Test case 7: List with negative numbers + self.assertTupleEqual(two_sum_brute_force([-1, 0, 1, 2, 3], 0), (0, 2)) + + def test_two_sum_two_pointers(self) -> None: + """ + This test case is part of the unit tests for the `two_sum_using_two_pointers` function. + """ + + # Test case 1: Two unique indices with a valid sum + self.assertTupleEqual(two_sum_using_two_pointers([2, 7, 11, 15], 9), (0, 1)) + + # Test case 2: Two unique indices with an invalid sum + self.assertTupleEqual(two_sum_using_two_pointers([2, 7, 11, 15], 17), (0, 3)) + + # Test case 3: No indices with a valid sum + self.assertTupleEqual(two_sum_using_two_pointers( + [2, 7, 11, 15], 30), (-1, -1)) + + # Test case 4: Empty list + self.assertTupleEqual(two_sum_using_two_pointers([], 9), (-1, -1)) + + # Test case 5: Single element list + self.assertTupleEqual(two_sum_using_two_pointers([5], 10), (-1, -1)) + + # Test case 6: List with duplicate elements + self.assertTupleEqual(two_sum_using_two_pointers( + [2, 7, 11, 11, 15], 16), (-1, -1)) + + # Test case 7: List with negative numbers + self.assertTupleEqual(two_sum_using_two_pointers([-1, 0, 1, 2, 3], 0), (0, 2)) + +if __name__ == '__main__': + unittest.main() diff --git a/lc217_contains_duplicate.py b/lc217_contains_duplicate.py new file mode 100644 index 0000000..a3c2153 --- /dev/null +++ b/lc217_contains_duplicate.py @@ -0,0 +1,123 @@ +""" +Given an integer array nums, + return true if any value appears at least twice in the array, + and return false if every element is distinct. + +Example 1: +Input: nums = [1,2,3,1] +Output: true + +Example 2: +Input: nums = [1,2,3,4] +Output: false + +Example 3: +Input: nums = [1,1,1,3,3,4,3,2,4,2] +Output: true + +Constraints: + +1 <= nums.length <= 105 +-109 <= nums[i] <= 109 +""" + +import unittest + +def contains_duplication_builtin_set(nums: list[int]) -> bool: + """ + Check if the given list contains any duplicate elements. + Time Complexity: O(n) + This is because the method converts the list to a set, + which is an unordered collection of unique elements. + Converting a list to a set takes linear time in the size of the list. + Space Compleixty: O(n) + This is because the method creates a new set, + which requires additional memory to store the unique elements. + """ + nums_set = set(nums) + if len(nums) == len(nums_set): + return False + return True + + +def contains_duplication_bruteforce(nums: list[int]) -> bool: + """ + Check if the given list contains any duplicate elements. + Time complexity: O(n^2) + This is because the method uses nested loops + to compare each element with every other element in the list, + resulting in a quadratic time complexity. + Space complexity: O(1), + since it does not use any additional + data structures or memory beyond the input list itself. + """ + for i, num in enumerate(nums): + if num in nums[i+1:]: + return True + return False + + +class TestContainsDuplication(unittest.TestCase): + """ + Check if the given list contains any duplicate elements using different test methods. + """ + def test_contains_duplication(self): + """ + Check if the given list contains any duplicate elements. + """ + # Test case: List with duplicate elements + self.assertTrue(contains_duplication_builtin_set([1, 2, 3, 1])) + + # Test case: List with no duplicate elements + self.assertFalse(contains_duplication_builtin_set([1, 2, 3, 4])) + + # Test case: Empty list + self.assertFalse(contains_duplication_builtin_set([])) + + # Test case: Empty list + self.assertTrue(contains_duplication_builtin_set([1,1,1,3,3,4,3,2,4,2])) + + # Test case: List with negative numbers + self.assertTrue(contains_duplication_builtin_set([-1, -1, -2, -1, -2, -3])) + + # Test case: List with large numbers + self.assertTrue(contains_duplication_builtin_set([1000, 1000, 2000, 2000, 3000, 3000])) + + # Test case: List with one element + self.assertFalse(contains_duplication_builtin_set([1])) + + # Test case: List with all elements the same + self.assertTrue(contains_duplication_builtin_set([1, 1, 1, 1, 1, 1])) + + + def test_contains_duplication_bruteforce(self): + """ + Check if the given list contains any duplicate elements. + """ + # Test case: List with duplicate elements + self.assertTrue(contains_duplication_bruteforce([1, 2, 3, 1])) + + # Test case: List with no duplicate elements + self.assertFalse(contains_duplication_bruteforce([1, 2, 3, 4])) + + # Test case: Empty list + self.assertFalse(contains_duplication_bruteforce([])) + + # Test case: Empty list + self.assertTrue(contains_duplication_bruteforce([1,1,1,3,3,4,3,2,4,2])) + + # Test case: List with negative numbers + self.assertTrue(contains_duplication_bruteforce([-1, -1, -2, -1, -2, -3])) + + # Test case: List with large numbers + self.assertTrue(contains_duplication_bruteforce([1000, 1000, 2000, 2000, 3000, 3000])) + + # Test case: List with one element + self.assertFalse(contains_duplication_bruteforce([1])) + + # Test case: List with all elements the same + self.assertTrue(contains_duplication_bruteforce([1, 1, 1, 1, 1, 1])) + + +if __name__ == "__main__": + unittest.main() diff --git a/lc28_find_the_index_of.py b/lc28_find_the_index_of.py new file mode 100644 index 0000000..3076402 --- /dev/null +++ b/lc28_find_the_index_of.py @@ -0,0 +1,118 @@ +""" +Given two strings needle and haystack, + return the index of the first occurrence of needle in haystack, + or -1 if needle is not part of haystack. + + +Example 1: +Input: haystack = "sadbutsad", needle = "sad" +Output: 0 +Explanation: "sad" occurs at index 0 and 6. +The first occurrence is at index 0, so we return 0. + + +Example 2: +Input: haystack = "leetcode", needle = "leeto" +Output: -1 +Explanation: "leeto" did not occur in "leetcode", so we return -1. + + +Constraints: +1 <= haystack.length, needle.length <= 104 +haystack and needle consist of only lowercase English characters. +""" + +import unittest + +def find_index_by_default_str_find(haystack: str, needle: str) -> int: + """ + Using built-in function, find returns -1 if not found + Time Complexity:O(n), where n is the length of the haystack + Space Complexity: O(1), as it only uses constant space to store the indices + """ + return haystack.find(needle) + + +# word search by sliding window +def find_index_from_str(haystack: str, needle: str) -> int: + """ + Using search mechanism with for a word by word + Time Complexity: O(n*m), + where n is the length of the haystack and m is the length of the needle. + Space Complexity: O(1), + s it only uses constant space to store the indices. + """ + for i in range(len(haystack) - len(needle) + 1): + if haystack[i:i + len(needle)] == needle: + return i + + return -1 + + +# sliding window +def find_index_from_str_using_sliding_window(haystack: str, needle: str) -> int: + """ + Using sliding window + Algorithm Used: Sliding Window + Time Complexity: O(n*m), + where n is the length of the haystack and m is the length of the needle. + Space Complexity: O(1), + as it only uses constant space to store the indices + """ + n = len(haystack) + m = len(needle) + for window_start in range(n - m + 1): + for find_str_index in range(m): + if haystack[window_start + find_str_index] != needle[find_str_index]: + break + if find_str_index == m - 1: + return window_start + return -1 + + +class TestFindIndex(unittest.TestCase): + """ + Find the occurence of a char or string (child) in a parent string + """ + def test_find_index_by_default_str_find(self) -> None: + """ + Testing method find_index_by_default_str_find + """ + self.assertEqual(find_index_by_default_str_find("sadbutsad", "sad"), 0) + self.assertEqual(find_index_by_default_str_find("sadbutsad", "but"), 3) + self.assertEqual(find_index_by_default_str_find("leetcode", "leet0"), -1) + self.assertEqual(find_index_by_default_str_find("interview", "e"),3) + self.assertEqual(find_index_by_default_str_find("kick start", "start"), 5) + self.assertEqual(find_index_by_default_str_find("kickstart", "n"), -1) + self.assertEqual(find_index_by_default_str_find("kickstart", " "), -1) + self.assertEqual(find_index_by_default_str_find(" ", "n"), -1) + + + def test_find_index_from_str(self) -> None: + """ + Testing method find_index_by_default_str_find + """ + self.assertEqual(find_index_from_str("sadbutsad", "sad"), 0) + self.assertEqual(find_index_from_str("sadbutsad", "but"), 3) + self.assertEqual(find_index_from_str("leetcode", "leet0"), -1) + self.assertEqual(find_index_from_str("interview", "e"),3) + self.assertEqual(find_index_from_str("kick start", "start"), 5) + self.assertEqual(find_index_from_str("kickstart", "n"), -1) + self.assertEqual(find_index_from_str("kickstart", " "), -1) + self.assertEqual(find_index_from_str(" ", "n"), -1) + + def test_find_index_from_str_using_sliding_window(self) -> None: + """ + Testing method find_index_by_default_str_find + """ + self.assertEqual(find_index_from_str_using_sliding_window("sadbutsad", "sad"), 0) + self.assertEqual(find_index_from_str_using_sliding_window("sadbutsad", "but"), 3) + self.assertEqual(find_index_from_str_using_sliding_window("leetcode", "leet0"), -1) + self.assertEqual(find_index_from_str_using_sliding_window("interview", "e"),3) + self.assertEqual(find_index_from_str_using_sliding_window("kick start", "start"), 5) + self.assertEqual(find_index_from_str_using_sliding_window("kickstart", "n"), -1) + self.assertEqual(find_index_from_str_using_sliding_window("kickstart", " "), -1) + self.assertEqual(find_index_from_str_using_sliding_window(" ", "n"), -1) + +if __name__ == "__main__": + unittest.main() diff --git a/lc349_intersection_of_arrays.py b/lc349_intersection_of_arrays.py new file mode 100644 index 0000000..75ab63a --- /dev/null +++ b/lc349_intersection_of_arrays.py @@ -0,0 +1,195 @@ +""" +349. Intersection of Two Arrays +Easy + +Given two integer arrays nums1 and nums2, return an array of their intersection +. Each element in the result must be unique and you may return the result in any order. + +Example 1: + +Input: nums1 = [1,2,2,1], nums2 = [2,2] +Output: [2] +Example 2: + +Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4] +Output: [9,4] +Explanation: [4,9] is also accepted. + +Constraints: + +1 <= nums1.length, nums2.length <= 1000 +0 <= nums1[i], nums2[i] <= 1000 +""" + +import unittest + +def intersection_by_bruteforce(nums1: list[int], nums2: list[int]) -> list[int]: + """ + Traverse both arrays + The time complexity of this function is O(n^2) + because it needs to traverse both nums1 and nums2 to find the intersection. + The space complexity is O(n) + because the size of the result list can grow up to the size + of the smaller of nums1 and nums2. + """ + result = [] + + # input validation + if nums1 is None or nums2 is None: + return result + + # traverse both arrays + for num in nums1: + if num in nums2 and num not in result: + result.append(num) + return result + +def intersection_by_list_comprehension(nums1: list[int], nums2: list[int]) -> list[int]: + """ + Using list comprehension + """ + result = set(x for x in nums1 if x in nums2) + return list(sorted(result)) + +def intersection_by_set(nums1: list[int], nums2: list[int]) -> list[int]: + """ + Using set + The time complexity of the intersection_by_set function is O(n + m), + where n is the length of nums1 and m is the length of nums2. + This is because creating a set from a list is O(n) + and finding the intersection of two sets is O(m). + + The space complexity of the intersection_by_set function is O(n + m), + where n is the length of nums1 and m is the length of nums2. + This is because creating a set from a list is O(n) + and finding the intersection of two sets is O(m). + The result list is O(k), where k is the size of the intersection. + + Note that the time and space complexity can be improved to O(n + m) and O(k) + respectively if we use a hash table instead of a set. + """ + if not nums1 or not nums2: + return [] + set1 = set(nums1) + set2 = set(nums2) + return list(sorted(set1.intersection(set2))) + +def intersection_by_hash(nums1: list[int], nums2: list[int]) -> list[int]: + """ + Using hash table + The time complexity of the intersection_by_hash function is O(n + m), + where n is the length of nums1 and m is the length of nums2. + This is because creating a hash table from a list is O(n) + and finding the intersection of two hash tables is O(m). + + The space complexity of the intersection_by_hash function is O(n + m), + where n is the length of nums1 and m is the length of nums2. + This is because creating a hash table from a list is O(n) + and finding the intersection of two hash tables is O(m). + The result list is O(k), where k is the size of the intersection. + """ + if not nums1 or not nums2: + return [] + hash_table = {} + for num in nums1: + hash_table[num] = True + result = [] + for num in nums2: + if num in hash_table and num not in result: + result.append(num) + return sorted(result) # hash table doesn't keep the order + +def intersection_by_two_pointers(nums1: list[int], nums2: list[int]) -> list[int]: + """ + Using Two pointers, + one pointer to one list and another pointer to another list + """ + result = [] + + # Input validation + if not nums1 or not nums2: + return result + + # sort the list before using two pointers + nums1.sort() + nums2.sort() + + # two pointers + i, j = 0, 0 + while i < len(nums1) and j < len(nums2): + if nums1[i] == nums2[j]: + if not result or result[-1] != nums1[i]: + result.append(nums1[i]) + i += 1 + j += 1 + elif nums1[i] < nums2[j]: + i += 1 + else: + j += 1 + + return result + +class TestIntersectionOfArrays(unittest.TestCase): + """ + Test the intersection of arrays problem. + + This function tests the intersection of arrays problem with different input + combinations and asserts the expected result. + """ + def test_intersection_of_arrays_by_set(self): + """ + This function test intersection of arrays using set logic + """ + self.assertEqual(intersection_by_set([1, 2, 2, 1], [2, 2]), [2]) + self.assertEqual(intersection_by_set([4, 9, 5], [9, 4, 9, 8, 4]), [4, 9]) + self.assertEqual(intersection_by_set([], [1, 2, 3]), []) + self.assertEqual(intersection_by_set([1, 2, 3], []), []) + self.assertEqual(intersection_by_set([1, 2, 3], [4, 5, 6]), []) + self.assertEqual(intersection_by_set([1, 2, 3], [1, 2, 3]), [1, 2, 3]) + + def test_intersection_of_arrays_by_bruteforce(self): + """ + This function test intersection of arrays with brute force + """ + self.assertEqual(intersection_by_bruteforce([1, 2, 2, 1], [2, 2]), [2]) + self.assertEqual(intersection_by_bruteforce([4, 9, 5], [9, 4, 9, 8, 4]), [4, 9]) + self.assertEqual(intersection_by_bruteforce([], [1, 2, 3]), []) + self.assertEqual(intersection_by_bruteforce([1, 2, 3], []), []) + self.assertEqual(intersection_by_bruteforce([1, 2, 3], [4, 5, 6]), []) + self.assertEqual(intersection_by_bruteforce([1, 2, 3], [1, 2, 3]), [1, 2, 3]) + + def test_intersection_of_arrays_by_two_pointers(self): + """ + This function test intersection of arrays using two pointers logic + """ + self.assertEqual(intersection_by_two_pointers([1, 2, 2, 1], [2, 2]), [2]) + self.assertEqual(intersection_by_two_pointers([4, 9, 5], [9, 4, 9, 8, 4]), [4, 9]) + self.assertEqual(intersection_by_two_pointers([], [1, 2, 3]), []) + self.assertEqual(intersection_by_two_pointers([1, 2, 3], []), []) + self.assertEqual(intersection_by_two_pointers([1, 2, 3], [4, 5, 6]), []) + self.assertEqual(intersection_by_two_pointers([1, 2, 3], [1, 2, 3]), [1, 2, 3]) + + def test_intersection_of_arrays_by_has_table(self): + """ + This function test intersection of arrays using hash table logic + """ + self.assertEqual(intersection_by_hash([1, 2, 2, 1], [2, 2]), [2]) + self.assertEqual(intersection_by_hash([4, 9, 5], [9, 4, 9, 8, 4]), [4, 9]) + self.assertEqual(intersection_by_hash([], [1, 2, 3]), []) + self.assertEqual(intersection_by_hash([1, 2, 3], []), []) + self.assertEqual(intersection_by_hash([1, 2, 3], [4, 5, 6]), []) + self.assertEqual(intersection_by_hash([1, 2, 3], [1, 2, 3]), [1, 2, 3]) + + def test_intersection_of_arrays_by_list_comprehension(self): + """ + This function test intersection of arrays using hash table logic + """ + self.assertEqual(intersection_by_list_comprehension([1, 2, 2, 1], [2, 2]), [2]) + self.assertEqual(intersection_by_list_comprehension([4, 9, 5], [9, 4, 9, 8, 4]), [4, 9]) + self.assertEqual(intersection_by_list_comprehension([], [1, 2, 3]), []) + self.assertEqual(intersection_by_list_comprehension([1, 2, 3], []), []) + self.assertEqual(intersection_by_list_comprehension([1, 2, 3], [4, 5, 6]), []) + self.assertEqual(intersection_by_list_comprehension([1, 2, 3], [1, 2, 3]), [1, 2, 3]) + +if __name__ == '__main__': + unittest.main() diff --git a/lc58_length_of_a_last_word.py b/lc58_length_of_a_last_word.py new file mode 100644 index 0000000..fd2d035 --- /dev/null +++ b/lc58_length_of_a_last_word.py @@ -0,0 +1,99 @@ +""" +Given a string s consisting of words and spaces, return the length of the last word in the string. + +A word is a maximal +substring + consisting of non-space characters only. + + + +Example 1: + +Input: s = "Hello World" +Output: 5 +Explanation: The last word is "World" with length 5. +Example 2: + +Input: s = " fly me to the moon " +Output: 4 +Explanation: The last word is "moon" with length 4. +Example 3: + +Input: s = "luffy is still joyboy" +Output: 6 +Explanation: The last word is "joyboy" with length 6. + + +Constraints: + +1 <= s.length <= 104 +s consists of only English letters and spaces ' '. +There will be at least one word in s. +""" + +import unittest + +def length_of_last_word_default(s: str) -> int: + """ + By default implementation + Time complexity: O(n), where n is the length of the input string s. + This is because the algorithm needs to iterate through the entire string + Space Complexity: O(n) as well, + because it creates a new string by stripping whitespace + and splitting the original string into words + """ + return len(s.strip().split(" ")[-1]) + + +def length_of_last_word_by_reverse_search(s:str) -> int: + """ + By reverse search + Time complexity: O(n), where n is the length of the input string s. + This is because the algorithm needs to iterate through the entire string + Space Complexity: O(1), + because it does not create any additional data structures + that scale with the input size. + It only uses a fixed amount of space to store variables. + """ + s = s.strip() + for i in range(len(s)-1, 0, -1): + if s[i] == " ": + return len(s[i+1:]) + return len(s) + + +class TestLengthOfLastWord(unittest.TestCase): + """ + function correctly calculates the length of the last word in the string "Hello World". + It asserts that the function returns the value 5, + which is the length of the last word "World". + """ + def test_length_of_lastword_default(self): + """ + Test the `length_of_last_word_default` function by asserting + """ + self.assertEqual(length_of_last_word_default("Hello World"), 5) + self.assertEqual(length_of_last_word_default(" fly me to the moon "), 4) + self.assertEqual(length_of_last_word_default("luffy is still joyboy"), 6) + self.assertEqual(length_of_last_word_default(" "), 0) + self.assertEqual(length_of_last_word_default(""), 0) + self.assertEqual(length_of_last_word_default("a"), 1) + self.assertEqual(length_of_last_word_default("hi"), 2) + + + def test_length_of_lastword_by_reverse_search(self): + """ + Test the `length_of_last_word_default` function by asserting + """ + self.assertEqual(length_of_last_word_by_reverse_search("Hello World"), 5) + self.assertEqual(length_of_last_word_by_reverse_search(" fly me to the moon "), 4) + self.assertEqual(length_of_last_word_by_reverse_search("luffy is still joyboy"), 6) + self.assertEqual(length_of_last_word_by_reverse_search(" "), 0) + self.assertEqual(length_of_last_word_by_reverse_search(""), 0) + self.assertEqual(length_of_last_word_default("a"), 1) + self.assertEqual(length_of_last_word_default("hi"), 2) + + + +if __name__ == "__main__": + unittest.main() diff --git a/lc709_to_lowercase.py b/lc709_to_lowercase.py new file mode 100644 index 0000000..8606f24 --- /dev/null +++ b/lc709_to_lowercase.py @@ -0,0 +1,84 @@ +""" +Given a string s, + return the string after replacing every uppercase letter with the same lowercase letter. + + + +Example 1: +Input: s = "Hello" +Output: "hello" + +Example 2: +Input: s = "here" +Output: "here" + +Example 3: +Input: s = "LOVELY" +Output: "lovely" + + +Constraints: + +1 <= s.length <= 100 +s consists of printable ASCII characters. +""" +import unittest + +def convert_to_lowercase(s: str) -> str: + """ + Convert a given string in to lower case + """ + return s.lower() + + +def to_lower_case_impl(s: str) -> str: + """ + Do Python implementation of isupper and tolower. + + Args: + s (str): The input string. + + Returns: + str: The input string with all uppercase letters converted to lowercase. + """ + def is_upper_impl(x: str) -> bool: + """Check if a character is an uppercase letter.""" + return 'A' <= x <= 'Z' + + def to_lower_impl(x: str) -> str: + """Convert an uppercase letter to lowercase.""" + return chr(ord(x) | 32) + + return ''.join(to_lower_impl(x) if is_upper_impl(x) else x for x in s) + + + + +class TestConvertToLowercase(unittest.TestCase): + """ + Covert lower case test + """ + def test_convert_to_lowercase(self): + """ + Test convert_to_lowercase + """ + self.assertEqual(convert_to_lowercase("Hello"), "hello") + self.assertEqual(convert_to_lowercase("HELLO"), "hello") + self.assertEqual(convert_to_lowercase("HELLO WORLD"), "hello world") + self.assertEqual(convert_to_lowercase(""), "") + self.assertEqual(convert_to_lowercase("123"), "123") + + + def test_convert_to_lowercase_by_own_impl(self): + """ + Test convert_to_lowercase + """ + self.assertEqual(to_lower_case_impl("Hello"), "hello") + self.assertEqual(to_lower_case_impl("HELLO"), "hello") + self.assertEqual(to_lower_case_impl("HELLO WORLD"), "hello world") + self.assertEqual(to_lower_case_impl(""), "") + self.assertEqual(to_lower_case_impl("123"), "123") + + +if __name__ == "__main__": + unittest.main() diff --git a/lc724_find_pivot_index.py b/lc724_find_pivot_index.py new file mode 100644 index 0000000..73ae0d1 --- /dev/null +++ b/lc724_find_pivot_index.py @@ -0,0 +1,110 @@ +""" +Given an array of integers nums, calculate the pivot index of this array. +The pivot index is the index where + the sum of all the numbers strictly to the left of the index + is equal to the sum of all the numbers strictly to the index's right. + +If the index is on the left edge of the array, + then the left sum is 0 because there are no elements to the left. + This also applies to the right edge of the array. + Return the leftmost pivot index. + +If no such index exists, return -1. + +Example 1: +Input: nums = [1,7,3,6,5,6] +Output: 3 +Explanation: +The pivot index is 3. +Left sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11 +Right sum = nums[4] + nums[5] = 5 + 6 = 11 + +Example 2: +Input: nums = [1,2,3] +Output: -1 +Explanation: +There is no index that satisfies the conditions in the problem statement. +Example 3: + +Input: nums = [2,1,-1] +Output: 0 +Explanation: +The pivot index is 0. +Left sum = 0 (no elements to the left of index 0) +Right sum = nums[1] + nums[2] = 1 + -1 = 0 + +Constraints: +1 <= nums.length <= 104 +-1000 <= nums[i] <= 1000 + +Note: This question is the same as 1991: + https://leetcode.com/problems/find-the-middle-index-in-array/ +""" + +import unittest + +def pivot_index_by_bruteforces(nums: list[int]) -> int: + """ + Brute Force Solution + """ + for index in range(0, len(nums)): + left_sum = sum(nums[:index]) + right_sum = sum(nums[index+1:]) + if left_sum == right_sum: + return index + + return -1 + + +# better solution +def pivot_index_by_totality_sum(nums: list[int]) -> int: + """ + Find the sum of entire list and subtract left sum value until find an index + """ + summation = sum(nums) + left_sum = 0 + for i, x in enumerate(nums): + if left_sum == (summation - left_sum - x): + return i + left_sum += x + return -1 + + + + +class TestPivotIndex(unittest.TestCase): + """ + Test the `pivot_index_of an array` problem. + """ + def test_pivot_index_by_bruteforces(self): + """ + This function tests the `pivot_index_by_bruteforces` function + by asserting the expected output against the actual output. + It tests various input scenarios and verifies that the function + returns the correct pivot index. + """ + self.assertEqual(pivot_index_by_bruteforces([1, 7, 3, 6, 5, 6]), 3) + self.assertEqual(pivot_index_by_bruteforces([1, 2, 3]), -1) + self.assertEqual(pivot_index_by_bruteforces([2, 1, -1]), 0) + self.assertEqual(pivot_index_by_bruteforces([]), -1) + self.assertEqual(pivot_index_by_bruteforces([1]), 0) + self.assertEqual(pivot_index_by_bruteforces([1, -1, 1]), 0) + + + def test_pivot_index_by_totality_sum(self): + """ + This function tests the `pivot_index_by_totality_sum` function + by asserting the expected output against the actual output. + It tests various input scenarios and verifies that the function + returns the correct pivot index. + """ + self.assertEqual(pivot_index_by_totality_sum([1, 7, 3, 6, 5, 6]), 3) + self.assertEqual(pivot_index_by_totality_sum([1, 2, 3]), -1) + self.assertEqual(pivot_index_by_totality_sum([2, 1, -1]), 0) + self.assertEqual(pivot_index_by_totality_sum([]), -1) + self.assertEqual(pivot_index_by_totality_sum([1]), 0) + self.assertEqual(pivot_index_by_totality_sum([1, -1, 1]), 0) + + +if __name__ == '__main__': + unittest.main() diff --git a/lc7_reverse_an_integer.py b/lc7_reverse_an_integer.py new file mode 100644 index 0000000..9223357 --- /dev/null +++ b/lc7_reverse_an_integer.py @@ -0,0 +1,138 @@ +""" +Given a signed 32-bit integer x, return x with its digits reversed. + If reversing x causes the value to go outside the signed 32-bit integer range [-231, 231 - 1], + then return 0. + +Assume the environment does not allow you to store 64-bit integers (signed or unsigned). + +Example 1: +Input: x = 123 +Output: 321 + +Example 2: +Input: x = -123 +Output: -321 + +Example 3: +Input: x = 120 +Output: 21 + +""" + +import unittest +import math + + +def reverse_an_integer_using_string_method(num: int) -> int: + """ + Reverse an integer using string + Algorithm used: String conversion reverse + Time Complexity: O(n) - where n is the number of digits in the input integer + Space Complexity: O(n) - This is because the function creates a new string + to store the reversed digits of the input integer. + """ + len_of_int = len(str(abs(num))) + resultant_sign = -1 if num < 0 else 1 if num > 0 else 0 + if resultant_sign == 0: + return resultant_sign + str_num = str(abs(num)) + result = "" + for i in range(len_of_int): + result += str_num[-1:] + str_num = str_num[:-1] + result = int(result) + result = 0 if result > 2**31 - 1 else result + return result * resultant_sign + + +def reverse_an_integer_math(num: int) -> int: + """ + Using mathematical logrithm method + Algorithm used: Math log and div mod + Time Complexity: O(n) - where n is the number of digits in the input integer + Space Complexity: O(1) - it does not use any additional data structures or variables + to store the reversed integer + """ + resultant_sign = -1 if num < 0 else 1 if num > 0 else 0 + if resultant_sign == 0: + return resultant_sign + num = abs(num) + len_of_int = int(math.log10(abs(num))) + 1 + result = 0 + for i in range(len_of_int): + # add the result into the last digit of integer * 10 ^ length of integer-1 + result += (num % 10) * (10 ** (len_of_int - (i + 1))) + num = num // 10 + result = 0 if result > 2**31 - 1 else result + return result * resultant_sign + + +def reverse_an_integer_using_divmod(num: int) -> int: + """ + Using divmod method + Algorithm used: Math div and mod + Time Complexity: O(n) - where n is the number of digits in the input integer + Space Complexity: O(1) - it does not use any additional data structures or variables + to store the reversed integer + """ + # base case if num is 0 return the same + if num == 0: + return num + sign = -1 if num < 0 else 1 + sign = [1, -1][num < 0] + result, num = 0, abs(num) + while num: + num, mod = divmod(num, 10) + result = result * 10 + mod + if result > 2**31 - 1: + return 0 + return result * sign + + +class TestReverseAnInteger(unittest.TestCase): + """ + Test Reverse An Integer from string with various method + """ + + def test_reverse_an_integer_using_string_method(self) -> None: + """ + Using string method for reversing + """ + self.assertEqual(reverse_an_integer_using_string_method(321), 123) + self.assertEqual(reverse_an_integer_using_string_method(-321), -123) + self.assertEqual(reverse_an_integer_using_string_method(21), 12) + self.assertEqual(reverse_an_integer_using_string_method(3), 3) + self.assertEqual(reverse_an_integer_using_string_method(40), 4) + self.assertEqual(reverse_an_integer_using_string_method(240), 42) + self.assertEqual(reverse_an_integer_using_string_method(404), 404) + self.assertEqual(reverse_an_integer_using_string_method(0), 0) + + def test_reverse_an_integer_using_math_log_method(self) -> None: + """ + Using string method for reversing + """ + self.assertEqual(reverse_an_integer_math(321), 123) + self.assertEqual(reverse_an_integer_math(-321), -123) + self.assertEqual(reverse_an_integer_math(21), 12) + self.assertEqual(reverse_an_integer_math(3), 3) + self.assertEqual(reverse_an_integer_math(40), 4) + self.assertEqual(reverse_an_integer_math(240), 42) + self.assertEqual(reverse_an_integer_math(404), 404) + self.assertEqual(reverse_an_integer_math(0), 0) + + def test_reverse_an_integer_using_divmod_method(self) -> None: + """ + Using string method for reversing + """ + self.assertEqual(reverse_an_integer_using_divmod(321), 123) + self.assertEqual(reverse_an_integer_using_divmod(-321), -123) + self.assertEqual(reverse_an_integer_using_divmod(21), 12) + self.assertEqual(reverse_an_integer_using_divmod(3), 3) + self.assertEqual(reverse_an_integer_using_divmod(40), 4) + self.assertEqual(reverse_an_integer_using_divmod(240), 42) + self.assertEqual(reverse_an_integer_using_divmod(404), 404) + self.assertEqual(reverse_an_integer_using_divmod(0), 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e0005e3 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,55 @@ +aiohttp==3.9.5 +aiosignal==1.3.1 +annotated-types==0.7.0 +anyio==4.4.0 +appnope==0.1.4 +asttokens==2.4.1 +attrs==23.2.0 +certifi==2024.6.2 +charset-normalizer==3.3.2 +comm==0.2.2 +debugpy==1.8.1 +decorator==5.1.1 +distro==1.9.0 +executing==2.0.1 +frozenlist==1.4.1 +h11==0.14.0 +httpcore==1.0.5 +httpx==0.27.0 +idna==3.7 +iniconfig==2.0.0 +ipykernel==6.29.4 +ipython==8.25.0 +jedi==0.19.1 +jupyter_client==8.6.2 +jupyter_core==5.7.2 +matplotlib-inline==0.1.7 +multidict==6.0.5 +nest-asyncio==1.6.0 +openai==1.30.5 +packaging==24.0 +parso==0.8.4 +pexpect==4.9.0 +platformdirs==4.2.2 +pluggy==1.5.0 +prompt_toolkit==3.0.45 +psutil==5.9.8 +ptyprocess==0.7.0 +pure-eval==0.2.2 +pydantic==2.7.2 +pydantic_core==2.18.3 +Pygments==2.18.0 +pytest==8.2.1 +python-dateutil==2.9.0.post0 +pyzmq==26.0.3 +requests==2.32.3 +six==1.16.0 +sniffio==1.3.1 +stack-data==0.6.3 +tornado==6.4 +tqdm==4.66.4 +traitlets==5.14.3 +typing_extensions==4.12.1 +urllib3==2.2.1 +wcwidth==0.2.13 +yarl==1.9.4