Skip to content

Commit d960d9b

Browse files
authored
Merge pull request #148 from BrianLusina/feat/algorithms-two-pointers-valid-palindrome-2
feat(algorithms, two-pointers): valid palindrome with one character removal
2 parents 3f016f2 + d7c2a75 commit d960d9b

29 files changed

+169
-26
lines changed

DIRECTORY.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,18 @@
218218
* [Test Next Permutation](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/next_permutation/test_next_permutation.py)
219219
* Pair With Sum In Array
220220
* [Test Pair With Sum In Array](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/pair_with_sum_in_array/test_pair_with_sum_in_array.py)
221+
* Palindrome
222+
* Largest Palindrome Product
223+
* [Test Largest Palindrome Product](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/palindrome/largest_palindrome_product/test_largest_palindrome_product.py)
224+
* [Longest Palindrome](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/palindrome/longest_palindrome.py)
225+
* [Longest Palindromic Substring](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/palindrome/longest_palindromic_substring.py)
226+
* [Palindrome Index](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/palindrome/palindrome_index.py)
227+
* [Palindrome Pairs](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/palindrome/palindrome_pairs.py)
228+
* Permutation Palindrome
229+
* [Test Permutation Palindrome](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/palindrome/permutation_palindrome/test_permutation_palindrome.py)
230+
* [Test Palindrome](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/palindrome/test_palindrome.py)
231+
* [Test Palindrome Index](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/palindrome/test_palindrome_index.py)
232+
* [Test Palindrome Pairs](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/palindrome/test_palindrome_pairs.py)
221233
* Rain Water Trapped
222234
* [Test Trapped Rain Water](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/two_pointers/rain_water_trapped/test_trapped_rain_water.py)
223235
* Reverse Array
@@ -844,18 +856,6 @@
844856
* [Test Max Vowels In Substring](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/max_vowels_in_substring/test_max_vowels_in_substring.py)
845857
* Merge Strings
846858
* [Test Merge Strings](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/merge_strings/test_merge_strings.py)
847-
* Palindrome
848-
* Largest Palindrome Product
849-
* [Test Largest Palindrome Product](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/palindrome/largest_palindrome_product/test_largest_palindrome_product.py)
850-
* [Longest Palindrome](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/palindrome/longest_palindrome.py)
851-
* [Longest Palindromic Substring](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/palindrome/longest_palindromic_substring.py)
852-
* [Palindrome Index](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/palindrome/palindrome_index.py)
853-
* [Palindrome Pairs](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/palindrome/palindrome_pairs.py)
854-
* Permutation Palindrome
855-
* [Test Permutation Palindrome](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/palindrome/permutation_palindrome/test_permutation_palindrome.py)
856-
* [Test Palindrome](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/palindrome/test_palindrome.py)
857-
* [Test Palindrome Index](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/palindrome/test_palindrome_index.py)
858-
* [Test Palindrome Pairs](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/palindrome/test_palindrome_pairs.py)
859859
* Pangram
860860
* [Test Pangram Checker](https://github.com/BrianLusina/PythonSnips/blob/master/pystrings/pangram/test_pangram_checker.py)
861861
* Parenthesis

algorithms/backtracking/partition_string/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from typing import List
2-
from pystrings.palindrome import is_palindrome
2+
from algorithms.two_pointers.palindrome import is_palindrome
33

44

55
def partition(s: str) -> List[List[str]]:

algorithms/greedy/jump_game/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,17 @@ target remains beyond index 0, then no path exists from the start to the end, an
6767

6868
#### Algorithm
6969

70-
1. We begin by setting the last index of the array as our initial target using the variable target = len(nums) - 1. This
70+
1. We begin by setting the last index of the array as our initial target using the variable `target = len(nums) - 1`. This
7171
target represents the position we are trying to reach, starting from the end and working backward. By initializing the
7272
target this way, we define our goal: to find out if there is any index i from which the target is reachable based on the
7373
value at that position, nums[i]. This also sets the stage for updating the target if such an index is found.
7474

75-
2. Next, we loop backward through the array using for i in range(len(nums) - 2, -1, -1). Here, i represents the current
75+
2. Next, we loop backward through the array using `for i in range(len(nums) - 2, -1, -1)`. Here, `i` represents the current
7676
index we are analyzing. At each index i, the value nums[i] tells us how far we can jump forward from that position.
77-
By checking whether i + nums[i] >= target, we determine whether it can reach the current target from index i. This
77+
By checking whether `i + nums[i] >= target`, we determine whether it can reach the current target from index i. This
7878
step allows us to use the jump range at each position to decide if it can potentially lead us to the end.
7979

80-
3. If the condition i + nums[i] >= target is TRUE, the current index i can jump far enough to reach the current target.
80+
3. If the condition `i + nums[i] >= target` is TRUE, the current index i can jump far enough to reach the current target.
8181
In that case, we update target = i, effectively saying, “Now we just need to reach index i instead.” If the condition
8282
fails, we move back in the array one step further and try again with the previous index.
8383
We repeat this process until we either:

pystrings/palindrome/README.md renamed to algorithms/two_pointers/palindrome/README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,82 @@ As only a few variables are used, the space complexity of this solution is O(1).
196196
- String
197197
- Dynamic Programming
198198
- Two Pointers
199+
200+
---
201+
202+
## Valid Palindrome II
203+
204+
Write a function that takes a string as input and checks whether it can be a valid palindrome by removing at most one
205+
character from it.
206+
207+
### Constraints
208+
209+
- 1 <= `s.length` <= 10^5
210+
- The string only consists of English letters
211+
212+
### Examples
213+
214+
Example 1:
215+
216+
```text
217+
Input: s = "aba"
218+
Output: true
219+
```
220+
221+
Example 2:
222+
223+
```text
224+
Input: s = "abca"
225+
Output: true
226+
Explanation: You could delete the character 'c'.
227+
```
228+
229+
Example 3:
230+
231+
```text
232+
Input: s = "abc"
233+
Output: false
234+
```
235+
236+
### Solution
237+
238+
The algorithm uses a two-pointer technique to determine whether a string is a palindrome or can be transformed into it
239+
by removing at most one character, where one pointer starts at the beginning and the other at the end. As the pointers
240+
move toward each other, they compare the corresponding characters. If all pairs match, the string is a palindrome.
241+
However, if a mismatch is detected, the algorithm explores two possibilities: removing the character at either pointer
242+
and checking if the resulting substring forms a palindrome. If either check passes, the function returns TRUE; otherwise,
243+
it returns FALSE.
244+
245+
The algorithm consists of two functions:
246+
247+
- `is_substring_palindrome(left, right)`: This helper function checks if a substring of the input string, defined by
248+
`left` and `right` indexes, is a palindrome. It uses a two-pointer approach, comparing characters from both ends
249+
inward. If any mismatch is found, it returns FALSE; otherwise, it returns TRUE.
250+
- `is_valid_palindrome_with_one_char_removal(string)`: This function checks if the entire string is a palindrome or can
251+
become one by removing one character. It initializes two pointers, `left_pointer` at the start and `right_pointer` at
252+
end of the string:
253+
- If the characters at the `left_pointer` and `right_pointer` are the same, it moves both pointers inward.
254+
- If the characters differ, it checks two cases by calling is_substring_palindrome:
255+
- The substring from `left_pointer + 1` to `right_pointer`
256+
- The substring from `left_pointer` to `right_pointer - 1`
257+
- If either case returns TRUE, the function returns TRUE; otherwise, it returns FALSE.
258+
259+
If the traversal completes without finding a mismatch, the string is a palindrome, and the function returns TRUE.
260+
261+
![Solution 1](./images/solutions/is_valid_palindrome_with_one_char_removal_solution_1.png)
262+
![Solution 2](./images/solutions/is_valid_palindrome_with_one_char_removal_solution_2.png)
263+
![Solution 3](./images/solutions/is_valid_palindrome_with_one_char_removal_solution_3.png)
264+
![Solution 4](./images/solutions/is_valid_palindrome_with_one_char_removal_solution_4.png)
265+
![Solution 5](./images/solutions/is_valid_palindrome_with_one_char_removal_solution_5.png)
266+
![Solution 6](./images/solutions/is_valid_palindrome_with_one_char_removal_solution_6.png)
267+
![Solution 7](./images/solutions/is_valid_palindrome_with_one_char_removal_solution_7.png)
268+
![Solution 8](./images/solutions/is_valid_palindrome_with_one_char_removal_solution_8.png)
269+
![Solution 9](./images/solutions/is_valid_palindrome_with_one_char_removal_solution_9.png)
270+
271+
#### Time Complexity
272+
273+
The time complexity of the solution above is O(n), where n is the length of the string
274+
275+
#### Space Complexity
276+
277+
The space complexity of solution above is O(1).

pystrings/palindrome/__init__.py renamed to algorithms/two_pointers/palindrome/__init__.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,45 @@ def is_palindrome_number_2(x: int) -> bool:
162162
left += 1
163163
right -= 1
164164
return True
165+
166+
167+
def is_valid_palindrome_with_one_char_removal(s: str) -> bool:
168+
"""
169+
Checks if a string s can become a valid palindrome with at most one character removal. Returns True if it can, False
170+
otherwise
171+
Args:
172+
s (str): string to check
173+
Returns:
174+
bool: True if after removal of at most one character, the string becomes a valid palindrome, otherwise False
175+
"""
176+
left_pointer = 0
177+
right_pointer = len(s) - 1
178+
179+
def is_substring_palindrome(left: int, right: int) -> bool:
180+
"""
181+
Checks if a given substring is a valid palindrome
182+
Args:
183+
left(int): the left index on the string to check
184+
right(int): the right index on the string to check
185+
Returns:
186+
bool: True if the substring is a valid palindrome, else False
187+
"""
188+
while left < right:
189+
if s[left] != s[right]:
190+
return False
191+
left += 1
192+
right -= 1
193+
return True
194+
195+
while left_pointer < right_pointer:
196+
if s[left_pointer] != s[right_pointer]:
197+
# validate that the substrings are valid palindromes
198+
return is_substring_palindrome(
199+
left_pointer + 1, right_pointer
200+
) or is_substring_palindrome(left_pointer, right_pointer - 1)
201+
202+
# move the pointers as the characters are equal
203+
left_pointer += 1
204+
right_pointer -= 1
205+
206+
return True
42 KB
Loading
48.8 KB
Loading
52.6 KB
Loading
77.4 KB
Loading
83.5 KB
Loading

0 commit comments

Comments
 (0)