diff --git a/DIRECTORY.md b/DIRECTORY.md index 648a5ad4..7793f007 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -369,10 +369,24 @@ * Shell Sort * [Test Shell Sort](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/sorting/shell_sort/test_shell_sort.py) * Stack + * Asteroid Collision + * [Test Asteroid Collision](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/stack/asteroid_collision/test_asteroid_collision.py) + * Bracket Validator + * [Test Bracket Validator](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/stack/bracket_validator/test_bracket_validator.py) * Daily Temperatures * [Test Daily Temperatures](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/stack/daily_temperatures/test_daily_temperatures.py) + * Decimal To Binary + * [Test Decimal To Binary](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/stack/decimal_to_binary/test_decimal_to_binary.py) + * Decode String + * [Test Decode String](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/stack/decode_string/test_decode_string.py) * Minimum String Length After Removing Substrings * [Test Min Str Length After Removing Substrings](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/stack/minimum_string_length_after_removing_substrings/test_min_str_length_after_removing_substrings.py) + * Nextgreater + * [Test Next Greater](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/stack/nextgreater/test_next_greater.py) + * Removing Stars + * [Test Remove Starts](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/stack/removing_stars/test_remove_starts.py) + * Reverse String + * [Test Reverse String](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/stack/reverse_string/test_reverse_string.py) * Strings * Caeser Cipher * [Test Caeser](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/strings/caeser_cipher/test_caeser.py) @@ -901,21 +915,6 @@ * Queue * Recent Counter * [Test Recent Calls](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/queue/recent_counter/test_recent_calls.py) - * Stack - * Asteroid Collision - * [Test Asteroid Collision](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/stack/asteroid_collision/test_asteroid_collision.py) - * Bracket Validator - * [Test Bracket Validator](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/stack/bracket_validator/test_bracket_validator.py) - * Decimal To Binary - * [Test Decimal To Binary](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/stack/decimal_to_binary/test_decimal_to_binary.py) - * Decode String - * [Test Decode String](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/stack/decode_string/test_decode_string.py) - * Nextgreater - * [Test Next Greater](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/stack/nextgreater/test_next_greater.py) - * Removing Stars - * [Test Remove Starts](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/stack/removing_stars/test_remove_starts.py) - * Reverse String - * [Test Reverse String](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/stack/reverse_string/test_reverse_string.py) * Students And Lunch * [Test Students Lunch](https://github.com/BrianLusina/PythonSnips/blob/master/puzzles/students_and_lunch/test_students_lunch.py) * Trees @@ -972,6 +971,10 @@ * [Test Multiply 5](https://github.com/BrianLusina/PythonSnips/blob/master/pymath/multiply_5/test_multiply_5.py) * Perfect Square * [Test Perfect Squares](https://github.com/BrianLusina/PythonSnips/blob/master/pymath/perfect_square/test_perfect_squares.py) + * Power Of I + * [Test Power Of I](https://github.com/BrianLusina/PythonSnips/blob/master/pymath/power_of_i/test_power_of_i.py) + * Power Of Two + * [Test Power Of Two](https://github.com/BrianLusina/PythonSnips/blob/master/pymath/power_of_two/test_power_of_two.py) * Rectangle Area * [Test Compute Area](https://github.com/BrianLusina/PythonSnips/blob/master/pymath/rectangle_area/test_compute_area.py) * Reverse Integer @@ -1263,7 +1266,6 @@ * [Test Plus Minus](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pymath/test_plus_minus.py) * [Test Population Growth](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pymath/test_population_growth.py) * [Test Power Digit Sum](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pymath/test_power_digit_sum.py) - * [Test Power Of I](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pymath/test_power_of_i.py) * [Test Power Of Sum](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pymath/test_power_of_sum.py) * [Test Product Fib](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pymath/test_product_fib.py) * [Test Pythagorean Triplet](https://github.com/BrianLusina/PythonSnips/blob/master/tests/pymath/test_pythagorean_triplet.py) diff --git a/puzzles/stack/asteroid_collision/README.md b/algorithms/stack/asteroid_collision/README.md similarity index 100% rename from puzzles/stack/asteroid_collision/README.md rename to algorithms/stack/asteroid_collision/README.md diff --git a/puzzles/stack/asteroid_collision/__init__.py b/algorithms/stack/asteroid_collision/__init__.py similarity index 100% rename from puzzles/stack/asteroid_collision/__init__.py rename to algorithms/stack/asteroid_collision/__init__.py diff --git a/puzzles/stack/asteroid_collision/test_asteroid_collision.py b/algorithms/stack/asteroid_collision/test_asteroid_collision.py similarity index 100% rename from puzzles/stack/asteroid_collision/test_asteroid_collision.py rename to algorithms/stack/asteroid_collision/test_asteroid_collision.py diff --git a/puzzles/stack/bracket_validator/README.md b/algorithms/stack/bracket_validator/README.md similarity index 100% rename from puzzles/stack/bracket_validator/README.md rename to algorithms/stack/bracket_validator/README.md diff --git a/puzzles/stack/bracket_validator/__init__.py b/algorithms/stack/bracket_validator/__init__.py similarity index 100% rename from puzzles/stack/bracket_validator/__init__.py rename to algorithms/stack/bracket_validator/__init__.py diff --git a/puzzles/stack/bracket_validator/test_bracket_validator.py b/algorithms/stack/bracket_validator/test_bracket_validator.py similarity index 100% rename from puzzles/stack/bracket_validator/test_bracket_validator.py rename to algorithms/stack/bracket_validator/test_bracket_validator.py diff --git a/puzzles/stack/decimal_to_binary/README.md b/algorithms/stack/decimal_to_binary/README.md similarity index 100% rename from puzzles/stack/decimal_to_binary/README.md rename to algorithms/stack/decimal_to_binary/README.md diff --git a/puzzles/stack/decimal_to_binary/__init__.py b/algorithms/stack/decimal_to_binary/__init__.py similarity index 100% rename from puzzles/stack/decimal_to_binary/__init__.py rename to algorithms/stack/decimal_to_binary/__init__.py diff --git a/puzzles/stack/decimal_to_binary/test_decimal_to_binary.py b/algorithms/stack/decimal_to_binary/test_decimal_to_binary.py similarity index 100% rename from puzzles/stack/decimal_to_binary/test_decimal_to_binary.py rename to algorithms/stack/decimal_to_binary/test_decimal_to_binary.py diff --git a/puzzles/stack/decode_string/README.md b/algorithms/stack/decode_string/README.md similarity index 100% rename from puzzles/stack/decode_string/README.md rename to algorithms/stack/decode_string/README.md diff --git a/puzzles/stack/decode_string/__init__.py b/algorithms/stack/decode_string/__init__.py similarity index 100% rename from puzzles/stack/decode_string/__init__.py rename to algorithms/stack/decode_string/__init__.py diff --git a/puzzles/stack/decode_string/test_decode_string.py b/algorithms/stack/decode_string/test_decode_string.py similarity index 100% rename from puzzles/stack/decode_string/test_decode_string.py rename to algorithms/stack/decode_string/test_decode_string.py diff --git a/puzzles/stack/nextgreater/README.md b/algorithms/stack/nextgreater/README.md similarity index 100% rename from puzzles/stack/nextgreater/README.md rename to algorithms/stack/nextgreater/README.md diff --git a/puzzles/stack/nextgreater/__init__.py b/algorithms/stack/nextgreater/__init__.py similarity index 100% rename from puzzles/stack/nextgreater/__init__.py rename to algorithms/stack/nextgreater/__init__.py diff --git a/puzzles/stack/nextgreater/test_next_greater.py b/algorithms/stack/nextgreater/test_next_greater.py similarity index 100% rename from puzzles/stack/nextgreater/test_next_greater.py rename to algorithms/stack/nextgreater/test_next_greater.py diff --git a/puzzles/stack/removing_stars/README.md b/algorithms/stack/removing_stars/README.md similarity index 100% rename from puzzles/stack/removing_stars/README.md rename to algorithms/stack/removing_stars/README.md diff --git a/puzzles/stack/removing_stars/__init__.py b/algorithms/stack/removing_stars/__init__.py similarity index 100% rename from puzzles/stack/removing_stars/__init__.py rename to algorithms/stack/removing_stars/__init__.py diff --git a/puzzles/stack/removing_stars/test_remove_starts.py b/algorithms/stack/removing_stars/test_remove_starts.py similarity index 100% rename from puzzles/stack/removing_stars/test_remove_starts.py rename to algorithms/stack/removing_stars/test_remove_starts.py diff --git a/algorithms/stack/reverse_string/README.md b/algorithms/stack/reverse_string/README.md new file mode 100644 index 00000000..db564659 --- /dev/null +++ b/algorithms/stack/reverse_string/README.md @@ -0,0 +1,46 @@ +# Reverse String + +You are given a character array, s, representing a string. Write a function that reverses the array in-place. + +- The reversal must be done by modifying the original array directly. +- You cannot use extra memory beyond a constant amount O(1). + +## Constraints + +- 1 <= `s.length` <= 1000 +- Each `s[i]` is printable ASCII character + +## Examples + +![Example 1](./images/examples/reverse_string_example_1.png) +![Example 2](./images/examples/reverse_string_example_2.png) +![Example 3](./images/examples/reverse_string_example_3.png) + +## Solution + +As the input is given as a character array, the problem can be solved efficiently by reversing the array in place without +using extra space for another array. The key idea is that reversing means swapping the first character with the last, the +second with the second-last, and so on, until all characters are placed in the correct reversed order. + +To achieve this, we can use the two pointer technique: one pointer starts at the beginning of the array and the other at +the end. We swap the characters at each step at these two positions, then move the pointers closer toward the center. +This continues until the pointers meet or cross, ensuring all characters are reversed. + +The steps of the algorithm are as follows: + +1. Initialize two pointers: left at the start, and right at the end of the array. +2. While left < right: + - Swap the characters at s[left] and s[right]. + - Increment left by 1 and decrement right by 1 to move the pointers inward. +3. The process terminates once the left and right pointers meet simultaneously. + +### Time Complexity + +The solution’s time complexity is O(n), where nnn is the length of the input array, s. Each character in the string is +swapped at most once as the two pointers move toward the center. As every element is visited at most once, the overall +time complexity is O(n). + +### Space Complexity + +The solution’s space complexity is O(1), as the reversal is done in place using only two pointers (left and right). No +additional data structures are required, regardless of the input size.Thus, the overall space complexity remains O(1). \ No newline at end of file diff --git a/puzzles/stack/reverse_string/__init__.py b/algorithms/stack/reverse_string/__init__.py similarity index 52% rename from puzzles/stack/reverse_string/__init__.py rename to algorithms/stack/reverse_string/__init__.py index a61f9288..f0653652 100644 --- a/puzzles/stack/reverse_string/__init__.py +++ b/algorithms/stack/reverse_string/__init__.py @@ -1,3 +1,5 @@ +from typing import List + from datastructures.stacks.dynamic import DynamicSizeStack as Stack @@ -29,3 +31,33 @@ def reverse_string(text: str) -> str: reversed_string += stack.pop() return reversed_string + + +def reverse_string_char_array(s: List[str]) -> None: + """ + Reverses a character array in place using two-pointer technique. + + Reference: https://leetcode.com/problems/reverse-string/ + + Complexity: + Where n is the length of the input list + Time: O(n), each character is visited at most once + Space: O(1), only two pointers used, no extra data structures + + Args: + s (List[str]): character array to reverse in place + Returns: + None: modifies the input list in place + """ + if not s or len(s) == 1: + return + + # Initialize two pointers: left at start, right at end + left = 0 + right = len(s) - 1 + + # Swap characters while left is before right + while left < right: + s[left], s[right] = s[right], s[left] + left += 1 + right -= 1 diff --git a/algorithms/stack/reverse_string/images/examples/reverse_string_example_1.png b/algorithms/stack/reverse_string/images/examples/reverse_string_example_1.png new file mode 100644 index 00000000..dcb7022b Binary files /dev/null and b/algorithms/stack/reverse_string/images/examples/reverse_string_example_1.png differ diff --git a/algorithms/stack/reverse_string/images/examples/reverse_string_example_2.png b/algorithms/stack/reverse_string/images/examples/reverse_string_example_2.png new file mode 100644 index 00000000..a017f580 Binary files /dev/null and b/algorithms/stack/reverse_string/images/examples/reverse_string_example_2.png differ diff --git a/algorithms/stack/reverse_string/images/examples/reverse_string_example_3.png b/algorithms/stack/reverse_string/images/examples/reverse_string_example_3.png new file mode 100644 index 00000000..039b475b Binary files /dev/null and b/algorithms/stack/reverse_string/images/examples/reverse_string_example_3.png differ diff --git a/algorithms/stack/reverse_string/test_reverse_string.py b/algorithms/stack/reverse_string/test_reverse_string.py new file mode 100644 index 00000000..5cc3c51f --- /dev/null +++ b/algorithms/stack/reverse_string/test_reverse_string.py @@ -0,0 +1,30 @@ +import unittest +from typing import List +import copy +from parameterized import parameterized +from algorithms.stack.reverse_string import reverse_string, reverse_string_char_array + +REVERSE_STRING_CHAR_ARRAY_TEST_CASES = [ + (["a", "e", "i", "o", "u"], ["u", "o", "i", "e", "a"]), + (["A", "l", "e", "x"], ["x", "e", "l", "A"]), + (["p", "y", "t", "h", "o", "n"], ["n", "o", "h", "t", "y", "p"]), + (["x"], ["x"]), +] + + +class ReverseStringTestCase(unittest.TestCase): + def test_one(self): + text = "!evitacudE ot emocleW" + actual = reverse_string(text) + expected = "Welcome to Educative!" + self.assertEqual(expected, actual) + + @parameterized.expand(REVERSE_STRING_CHAR_ARRAY_TEST_CASES) + def test_reverse_string_char_array(self, s: List[str], expected: List[str]): + s_copy = copy.deepcopy(s) + reverse_string_char_array(s_copy) + self.assertEqual(expected, s_copy) + + +if __name__ == "__main__": + unittest.main() diff --git a/puzzles/stack/__init__.py b/puzzles/stack/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/puzzles/stack/reverse_string/README.md b/puzzles/stack/reverse_string/README.md deleted file mode 100644 index 27cd63df..00000000 --- a/puzzles/stack/reverse_string/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Reverse a string using a stack - -This demonstrates how to reverse a string using a stack data structure \ No newline at end of file diff --git a/puzzles/stack/reverse_string/test_reverse_string.py b/puzzles/stack/reverse_string/test_reverse_string.py deleted file mode 100644 index 4e6bc6f0..00000000 --- a/puzzles/stack/reverse_string/test_reverse_string.py +++ /dev/null @@ -1,14 +0,0 @@ -import unittest -from . import reverse_string - - -class ReverseStringTestCase(unittest.TestCase): - def test_one(self): - text = "!evitacudE ot emocleW" - actual = reverse_string(text) - expected = "Welcome to Educative!" - self.assertEqual(expected, actual) - - -if __name__ == "__main__": - unittest.main()