-
Notifications
You must be signed in to change notification settings - Fork 2
feat(algorithms, stack): min str length after removing substrings #177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
efd1b81
feat(algorithms, stack): min str length after removing substrings
BrianLusina 27e0212
updating DIRECTORY.md
138533b
Update algorithms/stack/minimum_string_length_after_removing_substrin…
BrianLusina ef9930c
Update algorithms/search/binary_search/magnetic_force_between_two_bal…
BrianLusina f3d4c94
Update algorithms/search/binary_search/magnetic_force_between_two_bal…
BrianLusina 92bf438
Update algorithms/stack/minimum_string_length_after_removing_substrin…
BrianLusina 255b923
Update algorithms/search/binary_search/magnetic_force_between_two_bal…
BrianLusina File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
algorithms/search/binary_search/magnetic_force_between_two_balls/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| # Magnetic Force Between Two Balls | ||
|
|
||
| In the universe Earth C-137, Rick discovered a special form of magnetic force between two balls if they are put in his | ||
| new invented basket. Rick has n empty baskets, the ith basket is at position[i], Morty has m balls and needs to distribute | ||
| the balls into the baskets such that the minimum magnetic force between any two balls is maximum. | ||
|
|
||
| Rick stated that magnetic force between two different balls at positions x and y is |x - y|. | ||
|
|
||
| Given the integer array position and the integer m. Return the required force i.e. the maximum possible value of the | ||
| minimum magnetic force between any two balls after they have been placed in the baskets. | ||
|
|
||
| ## Examples | ||
|
|
||
| Example: | ||
|  | ||
|
|
||
| ```text | ||
| Input: position = [1,2,3,4,7], m = 3 | ||
| Output: 3 | ||
| Explanation: Distributing the 3 balls into baskets 1, 4 and 7 will make the magnetic force between ball pairs [3, 3, 6]. | ||
| The minimum magnetic force is 3. We cannot achieve a larger minimum magnetic force than 3 | ||
| ``` | ||
|
|
||
| ```text | ||
| Input: position = [5,4,3,2,1,1000000000], m = 2 | ||
| Output: 999999999 | ||
| Explanation: We can use baskets 1 and 1000000000. | ||
| ``` | ||
|
|
||
|  | ||
|  | ||
|  | ||
|
|
||
|
|
||
| ## Constraints | ||
|
|
||
| - n == `position.length` | ||
| - 2 <= n <= 10^5 | ||
| - 1 <= position[i] <= 10^9 | ||
| - All integers in `position` are distinct. | ||
| - 2 <= `m` <= `position.length` | ||
|
|
||
| ## Topics | ||
|
|
||
| - Array | ||
| - Binary Search | ||
| - Sorting | ||
|
|
||
| ## Hints | ||
|
|
||
| - If you can place balls such that the answer is x then you can do it for y where y < x. | ||
| - Similarly if you cannot place balls such that the answer is x then you cannot do it for y where y > x. | ||
| - Binary search on the answer and greedily see if it is possible. |
50 changes: 50 additions & 0 deletions
50
algorithms/search/binary_search/magnetic_force_between_two_balls/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| from typing import List | ||
|
|
||
|
|
||
| def max_distance(position: List[int], m: int) -> int: | ||
| if not position: | ||
| return 0 | ||
| if m <= 1: | ||
| return 0 | ||
|
|
||
| result = 0 | ||
| n = len(position) | ||
| sorted_positions = sorted(position) | ||
|
|
||
| # initial search space | ||
| low = 1 | ||
| high = int(sorted_positions[-1] / (m - 1.0)) + 1 | ||
|
|
||
| def can_place_balls(x: int) -> bool: | ||
| """Check if we can place 'm' balls at 'position' with each ball having at least 'x' gap.""" | ||
|
|
||
| # place first ball at the first positions | ||
| prev_ball_position = sorted_positions[0] | ||
| balls_placed = 1 | ||
|
|
||
| # Iterate on each position and place a ball there if we can place it | ||
| for i in range(1, n): | ||
| current_position = sorted_positions[i] | ||
| # check if we can place the ball at the current position | ||
| if current_position - prev_ball_position >= x: | ||
| balls_placed += 1 | ||
| prev_ball_position = current_position | ||
| # if all m balls are placed return true | ||
| if balls_placed == m: | ||
| return True | ||
|
|
||
| return False | ||
|
|
||
| while low <= high: | ||
| mid = low + (high - low) // 2 | ||
| # if we can place all balls having a gap at least mid | ||
| if can_place_balls(mid): | ||
| # Then mid can be our answer | ||
| result = mid | ||
| # and discard the left-half search space | ||
| low = mid + 1 | ||
| else: | ||
| # discard the right-half search space | ||
| high = mid - 1 | ||
|
|
||
| return result | ||
Binary file added
BIN
+63.8 KB
...etween_two_balls/images/examples/magnetic_force_between_two_balls_example_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+56.4 KB
...etween_two_balls/images/examples/magnetic_force_between_two_balls_example_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+65.7 KB
...etween_two_balls/images/examples/magnetic_force_between_two_balls_example_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+70.6 KB
...etween_two_balls/images/examples/magnetic_force_between_two_balls_example_4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions
27
...h/binary_search/magnetic_force_between_two_balls/test_magnetic_force_between_two_balls.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import unittest | ||
| from typing import List | ||
| from parameterized import parameterized | ||
| from algorithms.search.binary_search.magnetic_force_between_two_balls import ( | ||
| max_distance, | ||
| ) | ||
|
|
||
| MAGNETIC_FORCE_BETWEEN_TWO_BALLS_TEST_CASES = [ | ||
| ([1, 2, 3, 4, 7], 3, 3), | ||
| ([5, 4, 3, 2, 1, 1000000000], 2, 999999999), | ||
| ([1, 2, 3, 7, 11], 2, 10), | ||
| ([9, 8, 7, 3], 3, 2), | ||
| ([1, 3, 7, 9, 14], 5, 2), | ||
| ([1000, 1], 2, 999), | ||
| ([5, 10, 15, 20, 25, 30], 4, 5), | ||
| ] | ||
|
|
||
|
|
||
| class MagneticForceBetweenTwoBallsTestCase(unittest.TestCase): | ||
| @parameterized.expand(MAGNETIC_FORCE_BETWEEN_TWO_BALLS_TEST_CASES) | ||
| def test_max_distance(self, position: List[int], m: int, expected: int): | ||
| actual = max_distance(position, m) | ||
| self.assertEqual(expected, actual) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| unittest.main() |
219 changes: 219 additions & 0 deletions
219
algorithms/stack/minimum_string_length_after_removing_substrings/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,219 @@ | ||
| # Minimum String Length After Removing Substrings | ||
|
|
||
| You are given a string s consisting only of uppercase English letters. | ||
|
|
||
| You can apply some operations to this string where, in one operation, you can remove any occurrence of one of the | ||
| substrings "AB" or "CD" from s. | ||
|
|
||
| Return the minimum possible length of the resulting string that you can obtain. | ||
|
|
||
| Note that the string concatenates after removing the substring and could produce new "AB" or "CD" substrings. | ||
|
|
||
| ## Examples | ||
|
|
||
|  | ||
|  | ||
|  | ||
|
|
||
| Example 4: | ||
|
|
||
| ```text | ||
| Input: s = "ABFCACDB" | ||
| Output: 2 | ||
| Explanation: We can do the following operations: | ||
| - Remove the substring "AB", so s = "FCACDB". | ||
| - Remove the substring "CD", so s = "FCAB". | ||
| - Remove the substring "AB", so s = "FC". | ||
| So the resulting length of the string is 2. | ||
| It can be shown that it is the minimum length that we can obtain. | ||
| ``` | ||
|
|
||
| Example 5: | ||
|
|
||
| ```text | ||
| Input: s = "ACBBD" | ||
| Output: 5 | ||
| Explanation: We cannot do any operations on the string so the length remains the same. | ||
| ``` | ||
|
|
||
| ## Constraints | ||
|
|
||
| - 1 ≤ `s.length` ≤ 100 | ||
| - s consists only of uppercase English letters. | ||
|
|
||
| ## Topics | ||
|
|
||
| - String | ||
| - Stack | ||
| - Simulation | ||
|
|
||
| ## Hints | ||
|
|
||
| - Can we use brute force to solve the problem? | ||
| - Repeatedly traverse the string to find and remove the substrings “AB” and “CD” until no more occurrences exist. | ||
| - Can the solution be optimized using a stack? | ||
|
|
||
| ## Solution(s) | ||
|
|
||
| 1. [String Replace](#string-replace) | ||
| 2. [Stack](#stack) | ||
| 3. [In Place Manipulation](#in-place-manipulation) | ||
|
|
||
| ### String Replace | ||
|
|
||
| The core issue with this problem is the ripple effect of removing substrings. When we delete one occurrence of "AB" or | ||
| "CD", it can create another substring that also needs removal. For example, in "CABD", if we remove "AB", we are left | ||
| with "CD", which must also be eliminated to minimize the string length. | ||
|
|
||
| A brute force approach will be to continuously check the string for "AB" and "CD" and remove them until none are left. | ||
| Once the loop ends, the string will have no remaining "AB" or "CD", and we can return its length. Many programming | ||
| languages offer built-in functions for finding and removing substrings, which will be helpful here. | ||
|
|
||
| > Note: Some programming practices suggest avoiding direct modifications to input data. If this applies, consider | ||
| > making a copy of the input string before you start. It’s a good idea to clarify this with your interviewer before you | ||
| > implement the solution. | ||
|
|
||
| **Algorithm** | ||
|
|
||
| - Enter a loop that continues while s contains either "AB" or "CD". | ||
| - Check if s contains "AB": | ||
| - If "AB" is present, remove all occurrences of "AB" from s. | ||
| - If "AB" is not present, check if s contains "CD". | ||
| - If "CD" is present, remove all occurrences of "CD" from s. | ||
| - After the loop ends, return the length of s. | ||
|
|
||
| #### Complexity Analysis | ||
|
|
||
| Let `n` be the length of the input string `s`. | ||
|
|
||
| ##### Time Complexity | ||
|
|
||
| The outer while loop can run up to `n/2` times in the worst case. This occurs when we remove two characters in each | ||
| iteration (e.g., for a string like "ABABABAB"). Inside the loop, the string methods need to scan the entire string, | ||
| which takes O(n) time. | ||
|
|
||
| Thus, the overall time complexity of the algorithm is `O(n/2⋅n)=O(n^2)`. | ||
|
|
||
| ##### Space Complexity | ||
|
|
||
| In Python3 and Java, strings are immutable. So, each string operation creates a new string object. However, at any given | ||
| time, we only need to store one version of the processed string. So, the space complexity is `O(n)`. | ||
|
|
||
| However, in C++, strings are mutable. So, string operations like erase() are performed in place. Thus, the space | ||
| complexity in C++ is `O(1)`. | ||
|
|
||
| ### Stack | ||
|
|
||
| In the string removal process, we face two choices for each character: | ||
|
|
||
| - Keep the character if it does not form a removable pattern. | ||
| - Remove it along with the previous character if it completes a pattern. | ||
|
|
||
| Using a stack simplifies this task. We push characters onto the stack as we read them and pop them off when we find a | ||
| pattern. | ||
|
|
||
| We read the input string from left to right. For each character, we decide to either add it to the stack or remove a | ||
| previous character. If the stack is not empty, we compare the current character with the top character on the stack. | ||
| If they form "AB" or "CD," we pop the stack. We do not push the current character, thus removing both characters. If | ||
| there is no pattern, we push the current character onto the stack. | ||
|
|
||
| After processing all characters, the remaining elements in the stack represent the minimum length of the string after | ||
| all possible removals. | ||
|
|
||
| **Algorithm** | ||
|
|
||
| - Initialize a stack to store the characters from the string. | ||
| - Iterate over each character in the input string s. For each character currentChar: | ||
| - If the stack is empty, push currentChar onto the stack and continue to the next character. | ||
| - If the current character is 'B' and the top of the stack is 'A', remove the top element from the stack. | ||
| - If the current character is 'D' and the top of the stack is 'C', remove the top element from the stack. | ||
| - If neither of the above conditions is met, push currentChar onto the stack. | ||
| - After processing all characters, return the size of the stack. | ||
|
|
||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|
|
||
| #### Complexity Analysis | ||
|
|
||
| Let `n` be the length of the input string `s`. | ||
|
|
||
| ##### Time Complexity | ||
|
|
||
| We iterate over each character of s exactly once. All stack operations inside the loop take constant time. Thus, the | ||
| time complexity of the algorithm is `O(n)`. | ||
|
|
||
| ##### Space Complexity | ||
|
|
||
| We use a stack to store characters from the input string. In the worst-case scenario, where no "AB" or "CD" patterns are | ||
| found, we would end up storing all n characters in the stack. Thus, the space complexity of the algorithm is `O(n)`. | ||
|
|
||
| ### In Place Manipulation | ||
|
|
||
| To optimize space, we can modify the string in place. | ||
|
|
||
| We use two pointers: | ||
|
|
||
| - Read Pointer (readPtr): This pointer moves from left to right through the string, checking each character. | ||
| - Write Pointer (writePtr): This pointer tracks where to write the next character we want to keep. | ||
|
|
||
| We start by setting writePtr to 0. As we move readPtr through the string, we copy the character at readPtr to the | ||
| position indicated by writePtr. Next, we check if the last two characters (positions writePtr-1 and writePtr) form a | ||
| removable pattern, such as "AB" or "CD". If they do, we decrease writePtr, which means we will overwrite this part in | ||
| the next steps. | ||
|
|
||
| If the last two characters do not form a removable pattern, we increment writePtr to point to the next position where | ||
| we can write a character. This way, we can effectively "remove" unwanted characters by overwriting them. | ||
|
|
||
| After processing all characters, the position of writePtr tells us the length of the final string. All the characters | ||
| we want to keep are now at the beginning of the array, up to the position of writePtr. | ||
|
|
||
|  | ||
|  | ||
|  | ||
BrianLusina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|  | ||
|  | ||
|  | ||
|  | ||
|  | ||
|
|
||
| **Algorithm** | ||
|
|
||
| - Initialize a variable writePtr to 0, which will keep track of the current write position. | ||
| - Iterate over each character in the string using a readPtr: | ||
| - Copy the character at readPtr to the position at writePtr in the string. | ||
| - Check if the following conditions are met: | ||
| - writePtr is greater than 0 (ensuring there's a previous character). | ||
| - The previous character (at writePtr - 1) is either 'A' or 'C'. | ||
| - The current character is exactly one ASCII value higher than the previous character. | ||
| - If these conditions are met: | ||
| - Decrement writePtr by 1, effectively removing the pair of characters. | ||
| - Else: | ||
| - Increment writePtr by 1, moving to the next position for writing. | ||
| - Return the value of writePtr, which represents the length of the remaining string after all removals. | ||
|
|
||
| #### Complexity Analysis | ||
|
|
||
| Let `n` be the length of the input string `s`. | ||
|
|
||
| ##### Time Complexity | ||
|
|
||
| We iterate through the input string exactly once. All operations within the loop take constant time. Thus, the overall | ||
| time complexity is linear, `O(n)`. | ||
|
|
||
| ##### Space Complexity | ||
|
|
||
| In Java and Python3, strings are immutable. So, the input string needs to be converted to an array or list to perform in | ||
| place modifications. Thus, the space complexity remains O(n). | ||
|
|
||
| String are mutable in C++. So, all modifications can be done on the input string itself. No additional data structures | ||
BrianLusina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| are used, so the space complexity is O(1). | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.