Longest Sub{string,array}¶
Prospect:¶
https://leetcode.com/problems/length-of-the-longest-alphabetical-continuous-substring/description/
Longest Consecutive x with k impurities (1-pass)¶
while shrink
Generic Solution: Longest Consecutive x with k Impurities (1-pass)¶
Solution
The goal is to identify the longest subarray within nums where the allowed value allowed appears consecutively, with up to k impurities (elements other than allowed). An impurity refers to any element in the array that differs from the specified allowed value. This is addressed using a variable-size sliding window technique that dynamically adjusts to maintain a valid subarray according to the problem’s constraints.
- Expansion:
The window expands by incrementing the
rightpointer. If the current element (nums[right]) is notallowed, increment the impurity count (count).This stage progressively includes more elements into consideration for forming the longest valid subarray.
- Shrinking:
The window shrinks from the left by incrementing the
leftpointer, reducing the impurity count as necessary to ensure the subarray remains valid (i.e.,countdoes not exceedk).The shrink process continues until the subarray meets the constraint of having at most
kimpurities, making it valid for evaluation.
- Logic:
After ensuring the current subarray is valid, update
maxito capture the length of the longest subarray found that satisfies the given conditions.
The solution iteratively adjusts the window size to explore all possible valid subarrays, ultimately returning the length of the longest one found.
Implementation Notes
Impurities are defined as elements within the subarray that differ from the
allowedvalue. The presence of more thankimpurities invalidates the current subarray.The expansion phase is handled incrementally with each iteration of the
while right < nloop, ensuring a gradual exploration of the array.The shrinking phase is crucial for maintaining the validity of the subarray, using a
whileloop to adjust the window size until the impurity constraint is satisfied.The approach emphasizes ensuring the subarray is valid before applying the problem-specific logic, a common intuition behind many sliding window problems.
Analysis
Time Complexity: O(N)
The algorithm iterates through each element of
numsonce, making adjustments to the sliding window as needed, leading to linear time complexity.
Space Complexity: O(1)
Constant extra space is utilized, with a few variables to track the window boundaries, impurity count, and maximum length found.
def longestAllowed(self, nums: List[Any], allowed: Any, k: int) -> int:
n = len(nums)
left = right = 0
count = maxi = 0
while right < n:
# Expansion
if nums[right] != allowed:
count += 1
right += 1
# Shrinking
while left < right and count > k:
if nums[left] != allowed:
count -= 1
left += 1
# Make sure the subarray is valid which abides all constraints of the problem statement
# That is, subarray should have at most 'k' impurities (other than allowed 'x')
maxi = max(maxi, right - left)
return maxi
1004. Max Consecutive Ones III (Medium)¶
Solution
The challenge is to find the maximum number of consecutive 1’s in the array nums after flipping at most k zeros to 1’s. This problem is effectively solved using a variable-size sliding window approach that dynamically adjusts to include as many 1’s as possible while allowing up to k zeros within the window.
The solution iterates through nums, expanding the window to include consecutive elements and using a counter (zeros) to track the number of zeros within the current window. The window shrinks as necessary to ensure that the count of zeros does not exceed k, thereby maintaining the validity of the window according to the problem’s constraints.
- Expansion:
Increment the
rightpointer to expand the window, increasing thezeroscounter if the current element is a zero.
- Shrinking:
If the
zeroscount exceedsk, increment theleftpointer to shrink the window from the left, decrementing thezeroscounter if a zero leaves the window. This step ensures the window remains valid under the given constraint.
- Logic:
After each adjustment, calculate the current window’s length (
right - left) if it is valid (i.e., contains at mostkzeros). Updatemaxito keep track of the maximum length found.
The function returns maxi, representing the length of the longest valid subarray found that satisfies the condition of having at most k zeros, effectively maximizing the number of consecutive 1’s.
Analysis
Time Complexity: O(N)
The algorithm iterates through the array
numsonce, with each element being considered for inclusion in the window exactly once. The linear scan, combined with efficient window adjustments, results in linear time complexity.
Space Complexity: O(1)
Constant extra space is utilized, with variables to track the window boundaries (
leftandright), the count of zeros within the window (zeros), and the maximum window length found (maxi).
def longestOnes(self, nums: List[int], k: int) -> int:
n = len(nums)
left = right = 0
zeros = maxi = 0
while right < n:
# Expansion
zeros += nums[right] == 0
right += 1
# Shrinking: until zeros<=k
while left < right and zeros > k:
zeros -= nums[left] == 0
left += 1
# Logic
# Make sure the subarray is valid which abides all constraints of the problem statement
# That is, subarray should have at most 'k' zeros
maxi = max(maxi, right - left)
return maxi
Using Generalized Approach:
def longestOnes(self, nums: List[int], k: int) -> int:
return self.longestAllowed(nums, allowed=1, k=k)
487. Max Consecutive Ones II (Medium)¶
Solution
This problem extends “Max Consecutive Ones” by allowing for at most one zero to be flipped to one, thereby increasing the length of a consecutive ones sequence. It can be directly solved by applying the generic solution longestAllowed, designed to find the longest sequence of a specified value (allowed = 1) with a tolerance for a limited number of impurities (k = 1).
The longestAllowed function, previously detailed, is adept at identifying the longest subarray meeting specific criteria—here, the maximum number of consecutive 1’s with up to one 0 allowed. By setting allowed to 1 and k to 1, the generic solution becomes tailored to this problem’s requirements.
- Implementation:
The solution is a straightforward application of the
longestAllowedfunction, passingnumsas the input array,allowedas 1 (target value), andkas 1 (allowing for one impurity, i.e., one zero to be flipped).
The function call self.longestAllowed(nums, allowed=1, k=1) returns the maximum length of a subarray in nums that consists of consecutive 1’s, considering that at most one 0 can be flipped to 1, directly addressing the “Max Consecutive Ones II” challenge.
Analysis
Time Complexity: O(N)
Leveraging the
longestAllowedfunction involves a single pass through the arraynums, adjusting the sliding window as necessary to find the longest valid subarray, thus ensuring linear time complexity.
Space Complexity: O(1)
The space complexity is constant, as the generic solution utilizes a fixed number of variables for its operation, independent of the input size.
def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
return self.longestAllowed(nums, allowed=1, k=1)
485. Max Consecutive Ones (Easy)¶
Solution
The problem seeks to identify the longest sequence of consecutive 1’s in the given binary array nums. This can be seamlessly addressed by the longestAllowed function, which is adept at locating the longest sequence of a specified value with a tolerance for a given number of impurities. For this problem, the allowed value is 1, and since no impurities (0’s) are permitted in the sequence, k is set to 0.
- Implementation:
Invoke the
longestAllowedfunction withnumsas the array to search,allowedas 1 to specify the target value, andkas 0 to indicate that no deviations from the target value are allowed. This effectively tailors the generic solution to find the longest sequence of consecutive 1’s without any interruptions by 0’s.
The function call self.longestAllowed(nums, allowed=1, k=0) directly computes the maximum length of a subarray in nums comprising consecutive 1’s, fitting the problem’s criteria perfectly.
Analysis
Time Complexity: O(N)
Utilizing the
longestAllowedfunction involves a single traversal through the arraynums, with the sliding window adjusting as needed to identify the longest valid subarray. This approach guarantees linear time complexity.
Space Complexity: O(1)
Constant space is utilized by the solution, as the generic method employs a fixed number of variables to conduct its operation, irrespective of the input array’s size.
def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
return self.longestAllowed(nums, allowed=1, k=0)
1493. Longest Subarray of 1’s After Deleting One Element (Medium)¶
Solution
This problem seeks the longest subarray of 1’s achievable by removing exactly one element from a binary array nums. The solution employs the longestAllowed function, apt for finding the longest sequence of a specified value with a limited number of impurities, here tailored to allow for one “impurity” (k = 1). An “impurity” in this context refers to a zero that can be “removed” or flipped to maintain a continuous sequence of ones.
However, the problem includes specific conditions that necessitate slight adjustments:
If
numsconsists entirely of 1’s, removing one element (a1) results in a subarray one element shorter than the original array (n - 1).In other cases, the longest sequence of 1’s with at most one
0is found usinglongestAllowed. The length of the subarray after deletion equates toright - left - 1, accounting for the removal of one0.
The element to be deleted can either be a 1 or a 0, affecting the calculation of the longest valid subarray.
- Implementation:
Apply
longestAllowedwithnumsas the array,allowed = 1for targeting sequences of 1’s, andk = 1for permitting one zero. The final result adjusts for the removal of one element by subtracting 1 from the computed length.
The function call self.longestAllowed(nums, allowed=1, k=1) - 1 computes the length of the longest subarray of 1’s possible after one deletion, conforming to the problem’s specifications.
Analysis
Time Complexity: O(N)
A single traversal through
numsis conducted by thelongestAllowedfunction, with linear time complexity ensured.
Space Complexity: O(1)
Constant space is utilized for the operation, as the solution employs a minimal number of variables, regardless of the input array’s size.
def longestSubarray(self, nums: List[int]) -> int:
return self.longestAllowed(nums, allowed=1, k=1) - 1
Longest Consecutive x with k impurities (>1-pass)¶
while shrink
1869. Longer Contiguous Segments of Ones than Zeros (Easy)¶
Solution
The goal is to determine if the longest contiguous segment of 1’s in the binary string s is longer than the longest contiguous segment of 0’s. This involves addressing two subproblems:
Finding the longest consecutive sequence of
"1"’s.Finding the longest consecutive sequence of
"0"’s.
Each subproblem can be solved by applying the longestAllowed function, originally designed to find the longest sequence of a specified value in an array, here adapted to work with binary strings. For this problem, the function is invoked twice, once for "1"’s and once for "0"’s, each time with k = 0 to ensure only contiguous segments are considered.
- Implementation:
Calculate the length of the longest consecutive
"1"’s usinglongestAllowed(s, allowed="1", k=0).Similarly, calculate the length of the longest consecutive
"0"’s usinglongestAllowed(s, allowed="0", k=0).Compare the lengths of these segments to determine if the segment of
"1"’s is longer than that of"0"’s.
The function checkZeroOnes returns True if the longest contiguous segment of "1"’s is greater than that of "0"’s, indicating the binary string s contains longer segments of 1’s than 0’s, as per the problem’s requirements.
Analysis
Time Complexity: O(N)
The
longestAllowedfunction is called twice, each time requiring a pass through the strings. Despite the two passes, the overall complexity remains linear in the length ofs.
Space Complexity: O(1)
The space used is constant, as the solution requires only variables to track the lengths of the longest segments and does not depend on the size of the input string.
def checkZeroOnes(self, s: str) -> bool:
ones = self.longestAllowed(s, allowed="1", k=0)
zeros = self.longestAllowed(s, allowed="0", k=0)
return ones > zeros
2024. Maximize the Confusion of an Exam (Medium)¶
Solution
The objective is to find the maximum number of consecutive correct answers (‘T’s) that can be achieved on an exam by flipping at most k incorrect answers (‘F’s) to correct (‘T’s), or vice versa. This entails addressing two subproblems:
Finding the longest sequence of consecutive
"T"’s with at mostk"F"’s replaced.Finding the longest sequence of consecutive
"F"’s with at mostk"T"’s replaced.
Each subproblem can be efficiently solved by applying the longestAllowed function, which is designed to find the longest sequence of a specified value with a tolerance for a limited number of impurities, here adapted for binary strings. For this problem, k impurities (either ‘T’ or ‘F’) are allowed to be replaced to maximize the sequence length.
- Implementation:
Calculate the longest sequence of
"T"’s by treating"F"’s as impurities and allowing up tokof them to be replaced, usinglongestAllowed(answerKey, allowed="T", k=k).Similarly, calculate the longest sequence of
"F"’s by treating"T"’s as impurities and allowing up tokreplacements, usinglongestAllowed(answerKey, allowed="F", k=k).Return the maximum of these two lengths to determine the maximum confusion (i.e., the maximum number of consecutive correct answers achievable through replacements).
The function maxConsecutiveAnswers returns the maximum achievable length of consecutive correct answers by optimally using replacements, as per the problem’s requirements.
Analysis
Time Complexity: O(N)
The
longestAllowedfunction is invoked twice—once for each possible value (‘T’ and ‘F’)—each requiring a single pass through theanswerKeystring. Despite the dual invocations, the overall time complexity remains linear in the length ofanswerKey.
Space Complexity: O(1)
Constant space is utilized, as the solution leverages a fixed number of variables to track the lengths of the longest segments and does not depend on the size of the input string.
def maxConsecutiveAnswers(self, answerKey: str, k: int) -> int:
max_con_T = self.longestAllowed(answerKey, allowed="T", k=k)
max_con_F = self.longestAllowed(answerKey, allowed="F", k=k)
return max(max_con_T, max_con_F)
Solution
In this alternative approach to maximizing the number of consecutive correct answers (‘T’s) by flipping at most k incorrect answers (‘F’s) to correct (‘T’s), or vice versa, we employ a one-pass sliding window technique. This method keeps a counter for both ‘T’s and ‘F’s within the window and adjusts the window size based on the number of impurities—defined here as the minimum of the counter values for ‘T’s and ‘F’s.
The sliding window expands to include more characters from the answer key, adjusting the counter accordingly. It then shrinks whenever the number of impurities (the lesser count of ‘T’s or ‘F’s within the window) exceeds k, ensuring that at most k replacements are needed to make all answers within the window the same. The length of each valid window is considered for calculating the maximum length of consecutive answers achievable with up to k flips.
- Implementation:
The window expands by incrementing the count for the current character (‘T’ or ‘F’) in
counteras therightpointer advances.The window shrinks by decrementing the count for the character at the
leftboundary of the window when the number of impurities exceedsk.After each adjustment, update
maxito capture the maximum length of a valid window encountered thus far.
The function maxConsecutiveAnswers returns the length of the longest subarray achievable under the constraint of making at most k replacements, effectively solving the problem with a single pass through the answer key.
Analysis
Time Complexity: O(N)
The algorithm iterates through the answer key exactly once with a sliding window, making adjustments to the window size and updating the counter as necessary. This ensures a linear time complexity relative to the length of the answer key.
Space Complexity: O(1)
Constant space is used, attributed to the counter that tracks the occurrences of ‘T’s and ‘F’s within the window and a few variables for managing the window and recording the maximum length found.
def maxConsecutiveAnswers(self, answerKey: str, k: int) -> int:
n = len(answerKey)
left = right = 0
counter = {"T": 0, "F": 0} # Counter for 'T's and 'F's within the window
maxi = 0
# Determine the lesser count of 'T's or 'F's
impurities = lambda: min(counter.values()) # OR
impurities = lambda: right - left - max(counter.values())
while right < n:
# Expansion: Include the current character and update its count
counter[answerKey[right]] += 1
right += 1
# Shrinking: Adjust the window if impurities exceed k
while left < right and impurities() > k:
counter[answerKey[left]] -= 1
left += 1
# Logic: Update maxi after ensuring the window is valid
maxi = max(maxi, right - left)
return maxi
424. Longest Repeating Character Replacement (Medium)¶
Solution
To maximize the length of a subarray where after replacing at most k characters, all characters in the subarray are the same, we iteratively apply the longestAllowed function across all unique characters in the string s. This accounts for two subproblems:
Finding the longest consecutive sequence of each character when at most
kdifferent characters are replaced.Comparing these lengths to determine the maximum achievable sequence length.
- Implementation:
For each unique character in
s, calculate the longest sequence achievable by allowing up tokreplacements of other characters, usinglongestAllowed.Determine the maximum length from these calculations to find the overall longest sequence after replacements.
The function characterReplacement returns the length of the longest subarray after replacements, optimized across all unique characters in s.
Analysis
Time Complexity: O(N * M)
Nis the length of strings, andMis the number of unique characters. ThelongestAllowedfunction is invoked once per unique character, each time requiring a pass throughs.
Space Complexity: O(M)
The space complexity depends on the storage required for tracking the longest sequences for each character, which is proportional to the number of unique characters.
def characterReplacement(self, s: str, k: int) -> int:
maxi = 0
for char in set(s):
maxi = max(maxi, self.longestAllowed(s, allowed=char, k=k))
return maxi
Solution
This one-pass solution employs a sliding window and a counter to track the frequency of characters within the window, maximizing the length of the subarray that can become uniform with at most k character replacements.
The window dynamically adjusts to include characters from s, updating the character frequencies. It shrinks whenever the number of replacements needed to equalize the window exceeds k, ensuring that each considered window is viable under the problem’s constraints.
- Implementation:
Expand the window by including the current character and updating its frequency in the counter.
Shrink the window if the number of necessary replacements (impurities) exceeds
k, ensuring the window’s validity.Continuously update
maxito reflect the maximum length of a valid window encountered.
The function characterReplacement returns the longest length of a subarray that can be made uniform with up to k replacements, determined efficiently with a single pass through s.
Analysis
Time Complexity: O(N)
The algorithm iterates through the string
sonce, adjusting the sliding window and the counter as necessary, ensuring linear time complexity.
Space Complexity: O(1)
Constant space is utilized, attributed to the counter that tracks character frequencies within the window and a few variables for managing the window and recording the maximum length found.
def characterReplacement(self, s: str, k: int) -> int:
n = len(s)
left = right = 0
counter = collections.Counter()
maxi = 0
impurities = lambda: right - left - max(counter.values())
while right < n:
# Expansion
counter[s[right]] += 1
right += 1
# Shrinking
while left < right and impurities() > k:
counter[s[left]] -= 1
left += 1
# Logic
maxi = max(maxi, right - left)
return maxi
Hashmap - Unique Elements¶
while shrink
3. Longest Substring Without Repeating Characters (Medium)¶
Solution
The task is to find the length of the longest substring of a given string s that does not contain any repeating characters. This challenge is efficiently addressed using a sliding window approach coupled with a counter to track the frequency of characters within the current window.
The solution iterates through s, dynamically adjusting the window to always encompass a substring without repeating characters. The counter ensures that each character’s occurrence is monitored, facilitating the identification of unique substrings.
- Expansion:
The window expands by including the current character and updating its frequency in the
counteras therightpointer advances.
- Shrinking:
If a character repetition is detected (
not is_unique()), the window shrinks from the left by decrementing theleftpointer and adjusting thecounteraccordingly. This process continues until the substring within the window is unique again.
- Logic:
After each expansion (or necessary shrinking), the length of the current valid (unique) window (
right - left) is compared againstmaxi, the maximum length encountered so far, andmaxiis updated if a longer unique substring is found.
The function lengthOfLongestSubstring returns maxi, representing the length of the longest substring without repeating characters found within s.
Analysis
Time Complexity: O(N)
The algorithm performs a single pass through the string
s, with each character being considered exactly once for inclusion in the window. Adjustments to the window size and the counter are done in constant time, ensuring linear time complexity.
Space Complexity: O(26)
The space complexity is determined by the size of the
counter, which tracks the frequency of characters within the window. At worst case, s can contain all lower case alphabets.
def lengthOfLongestSubstring(self, s: str) -> int:
n = len(s)
left = right = 0
counter = collections.Counter()
maxi = 0
is_unique = lambda: len(counter) == right - left
while right < n:
# Expansion
counter[s[right]] += 1
right += 1
# Shrinking
while left < right and not is_unique():
counter[s[left]] -= 1
if counter[s[left]] == 0:
counter.pop(s[left])
left += 1
# Logic
maxi = max(maxi, right - left)
return maxi
1695. Maximum Erasure Value (Medium)¶
Solution
Can be restated as “Find the maximum sum of subarray with unique elements”.
The goal is to find the maximum score you can obtain by erasing a subarray from a given array nums. The score of a subarray is the sum of its elements, and the subarray to be erased must contain unique elements. This problem can be effectively solved using a sliding window approach, complemented by a counter to track the elements within the current window and ensure their uniqueness.
The solution iterates through nums, dynamically adjusting the window to always encompass a subarray with unique elements. The counter aids in monitoring each element’s presence within the window, while total keeps track of the current window’s score.
- Expansion:
The window expands by incorporating the current element into
totaland updating its frequency in thecounteras therightpointer moves forward.
- Shrinking:
If a repetition is detected (
not is_unique()), the window shrinks from the left by decrementing theleftpointer, adjusting thecounter, and subtracting the element’s value fromtotal. This continues until the window regains uniqueness.
- Logic:
After each adjustment, compare the current
totalagainstmaxi, updatingmaxiif a higher score is found. This ensures the maximum erasure value is recorded.
The function maximumUniqueSubarray returns maxi, the highest score obtainable by erasing a unique subarray from nums.
Analysis
Time Complexity: O(N)
A single pass through
numsis conducted, with each element being considered for inclusion in the window exactly once. The linear scan, combined with constant-time operations for each element (expansion, shrinking, and updatingtotalandmaxi), results in linear time complexity.
Space Complexity: O(26)
The space complexity is determined by the size of the
counter, which tracks the frequency of characters within the window. At worst case, s can contain all lower case alphabets.
def maximumUniqueSubarray(self, nums: List[int]) -> int:
n = len(nums)
left = right = 0
counter = collections.Counter()
maxi = total = 0
is_unique = lambda: right - left == len(counter)
while right < n:
# Expansion
counter[nums[right]] += 1
total += nums[right]
right += 1
# Shrinking
while left < right and not is_unique():
counter[nums[left]] -= 1
total -= nums[left]
if counter[nums[left]] == 0:
counter.pop(nums[left])
left += 1
# Logic
maxi = max(maxi, total)
return maxi
Hashmap - K Distinct Elements¶
while shrink
340. Longest Substring with At Most K Distinct Characters (Medium)¶
Solution
This problem aims to find the length of the longest substring that contains at most k distinct characters from a given string s. The challenge is efficiently addressed using a sliding window technique, complemented by a counter to track the frequency of each character within the current window.
The solution iterates through s, expanding the window to include more characters and using the counter to ensure the distinct character count within the window does not exceed k.
- Expansion:
The window expands by including the current character in the
counteras therightpointer advances, incrementing the character’s count.
- Shrinking:
If the distinct character count within the window exceeds
k, the window shrinks from the left by decrementing theleftpointer and adjusting thecounteraccordingly. This process continues until the window again contains at mostkdistinct characters.
- Logic:
After each expansion (or necessary shrinking), the length of the current valid window (
right - left) is compared againstmaxi, the maximum length encountered so far, andmaxiis updated if a longer substring is found.
The function lengthOfLongestSubstringKDistinct returns maxi, representing the length of the longest substring within s that contains at most k distinct characters.
Analysis
Time Complexity: O(N)
The algorithm performs a single pass through the string
s, with each character being considered exactly once for inclusion in the window. Adjustments to the window size and thecounterare done in constant time, ensuring linear time complexity.
Space Complexity: O(k)
The space complexity is influenced by the
counter, which tracks the frequency of characters within the window. In the worst case, the counter could contain up tokdistinct characters, indicating the space requirement is proportional tok.
def lengthOfLongestSubstringKDistinct(self, s: str, k: int) -> int:
n = len(s)
left = right = 0
counter = collections.Counter()
maxi = 0
# Function to check if the window contains at most k distinct characters
k_distinct = lambda: len(counter) <= k
while right < n:
# Expansion: Include the current character and update its count
counter[s[right]] += 1
right += 1
# Shrinking: Ensure the window does not exceed k distinct characters
while left < right and not k_distinct():
counter[s[left]] -= 1
if counter[s[left]] == 0:
counter.pop(s[left])
left += 1
# Update the maximum length found so far
maxi = max(maxi, right - left)
return maxi
159. Longest Substring with At Most Two Distinct Characters (Medium)¶
Solution
This problem is a specific instance of the broader challenge tackled in 340. Longest Substring with At Most K Distinct Characters (Medium) where k is set to 2. The task is to identify the length of the longest substring in a given string s that contains at most two distinct characters. By setting k = 2, we apply the previously outlined sliding window and counter strategy to solve this specialized version efficiently.
The solution directly utilizes the lengthOfLongestSubstringKDistinct function, previously described, by passing k = 2 as an argument. This adaptation allows for the same dynamic window adjustment and character tracking methodology to be employed, focusing on ensuring that no more than two distinct characters are present in any considered substring.
- Implementation:
The
lengthOfLongestSubstringKDistinctfunction is invoked withsas the input string andkset to 2. This approach seamlessly tailors the generic solution to meet the specific requirements of this problem, leveraging the logic developed for handling up tokdistinct characters in a substring.
The function lengthOfLongestSubstringTwoDistinct returns the maximum length of a substring in s that complies with the constraint of containing at most two distinct characters.
Analysis
Time Complexity: O(N)
Invoking
lengthOfLongestSubstringKDistinctwithk = 2entails a single pass through the strings, with linear time complexity ensured by the efficient sliding window and counter adjustments.
Space Complexity: O(k) = O(2) = O(1)
The space complexity is effectively constant, as the number of distinct characters tracked by the counter is limited to at most two in this specific scenario. This constraint bounds the additional space required, irrespective of the length of
s.
def lengthOfLongestSubstringTwoDistinct(self, s: str) -> int:
return self.lengthOfLongestSubstringKDistinct(s, k=2)
904. Fruit Into Baskets (Medium)¶
Solution
A special case of 340. Longest Substring with At Most K Distinct Characters (Medium), where k = 2.
Also, literally similar to 159. Longest Substring with At Most Two Distinct Characters (Medium), but in different words.
Analysis
Time Complexity: O(N)
Space Complexity: O(k) = O(2) = O(1)
def totalFruit(self, fruits: List[int]) -> int:
return self.lengthOfLongestSubstringKDistinct(fruits, k=2)
1446. Consecutive Characters (Easy)¶
Solution
This problem asks for the maximum power of a string s, defined as the maximum length of a non-empty substring that contains only one unique character. This problem is a specific instance of finding the longest substring with at most k distinct characters, where k = 1.
By utilizing the lengthOfLongestSubstringKDistinct function, which was designed to find the longest substring with up to k distinct characters, we can directly apply it to solve this problem. Setting k = 1 allows for the identification of the longest sequence of consecutive identical characters, aligning perfectly with the problem’s requirements.
- Implementation:
Invoke
lengthOfLongestSubstringKDistinctwithsas the input string andk = 1to specifically target sequences of consecutive identical characters.This method dynamically adjusts a sliding window to encompass the longest substring that satisfies the condition of having at most one distinct character.
The function maxPower leverages this approach to calculate the maximum power of s, effectively determining the length of the longest substring composed of consecutive identical characters.
Analysis
Time Complexity: O(N)
Employing
lengthOfLongestSubstringKDistinctwithk = 1entails a single traversal through the strings, maintaining linear time complexity due to the efficient sliding window mechanism.
Space Complexity: O(1)
The space complexity is constant, as the solution uses only a few variables for tracking the window’s boundaries and the maximum substring length, independent of the input string’s size.
def maxPower(self, s: str) -> int:
return self.lengthOfLongestSubstringKDistinct(s, k=1)
Depends on prev¶
while expand
674. Longest Continuous Increasing Subsequence (Easy)¶
Solution
The aim is to identify the length of the longest continuous increasing subsequence (LCIS) within an array nums. This challenge is effectively approached using a sliding window technique, tracking the current subsequence’s start and end points while monitoring for any breaks in the increasing sequence.
The solution iterates through nums, expanding the window to encompass consecutive elements that form an increasing sequence. The prev variable is used to compare the current element against the last, ensuring continuity in the increasing order.
- Expansion:
The window expands by moving the
rightpointer forward, as long as the current element is greater than the previous one (prev, essentiallynums[right - 1]). Theprevvariable is updated to reflect the most recent element in the sequence.
- Logic:
After each expansion or when an increasing sequence is interrupted, calculate the current window’s length (
right - left) and compare it againstmaxi, updatingmaxiif a longer subsequence is found.
- Shrinking:
Upon encountering an element that does not continue the increasing sequence, set
prevto the current element (or None if at the end of the array)Shrinking is done rapidly but without
whileloop. For the next expansion,leftstarts from the currentright. To avoid infinite outerwhileloop when right is never incremented inside the inner expansionwhileloop, we can start therightby incrementing1for the next expansion.
The function findLengthOfLCIS returns maxi, denoting the length of the longest continuous increasing subsequence found in nums.
Analysis
Time Complexity: O(N)
A single pass through the array
numsis conducted, with each element being evaluated exactly once to determine its contribution to a continuous increasing subsequence, ensuring linear time complexity.
Space Complexity: O(1)
Constant space is utilized, as the solution employs only a few variables (
left,right,maxi, andprev) to track the progress of the sliding window and record the maximum subsequence length.
def findLengthOfLCIS(self, nums: List[int]) -> int:
n = len(nums)
left = right = 0
maxi = 0
prev = -1
while right < n:
# Expansion
while right < n and prev < nums[right]:
prev = nums[right]
right += 1
# Logic
maxi = max(maxi, right - left)
# Shrinking
prev = nums[right] if right < n else None
left = right
right += 1
return maxi
1839. Longest Substring Of All Vowels in Order (Medium)¶
Solution
The task is to find the length of the longest beautiful substring in the given string word. A beautiful substring is defined as one that contains all five vowels (‘a’, ‘e’, ‘i’, ‘o’, ‘u’) in order and without any repetition. This problem can be solved using a sliding window approach, complemented by a set to track the unique vowels encountered within the current window.
The solution iterates through word, adjusting the window to capture sequences that potentially form a beautiful substring. The seen set records the vowels encountered to ensure the substring includes all required vowels in order.
- Expansion:
Expand the window by moving the
rightpointer forward, adding vowels to theseenset and updatingprevto maintain the order condition (i.e., the current character should not precede the previous one in the sequence).
- Logic:
After each expansion, if
seencontains all five vowels (indicating a beautiful substring), calculate the current window’s length (right - left) and updatemaxiif a longer beautiful substring is found.
- Shrinking:
Reset
seento prepare for identifying the next potential beautiful substring. Adjustprevto the current character atright(or None if at the end ofword), and setleftto start from the currentright, moving the window forward.
The function longestBeautifulSubstring returns maxi, denoting the length of the longest beautiful substring found in word.
Analysis
Time Complexity: O(N)
The algorithm performs a single pass through the string
word, with each character being considered for inclusion in the window exactly once. This approach, combined with constant-time operations for adjusting the window and updatingseen, ensures linear time complexity.
Space Complexity: O(1)
Constant space is used, as the solution employs a set to track the vowels within the current window and a few variables to manage the window’s boundaries and record the maximum substring length. The set
seenis limited to at most five elements (the vowels), indicating a constant space requirement.
def longestBeautifulSubstring(self, word: str) -> int:
n = len(word)
left = right = 0
seen = set()
maxi = 0
prev = word[0]
while right < n:
# Expansion
while right < n and prev <= word[right]:
prev = word[right]
seen.add(word[right])
right += 1
# Logic
if len(seen) == 5:
maxi = max(maxi, right - left)
# Shrinking
seen = set()
prev = word[right] if right < n else None
left = right
return maxi
Miscellaneous¶
1208. Get Equal Substrings Within Budget (Medium)¶
Solution
The problem asks for the maximum length of a non-empty substring of s that can be made equal to the corresponding substring of t, under the condition that the total cost of making all characters of the substring equal does not exceed maxCost. The cost of changing a character to another character is equal to the absolute difference in their ASCII values. This solution employs a sliding window approach, where the window dynamically adjusts to maximize the substring length while keeping the total cost within the budget.
- Expansion:
Expand the window by incrementally including characters from the right, calculating the cost for each new character added to the window. The cost is determined by the absolute difference in ASCII values between corresponding characters in
sandt.
- Shrinking:
If the total cost exceeds
maxCost, shrink the window from the left by removing characters until the total cost is within the budget again.
- Logic:
After each valid expansion (where the total cost is within the budget) or necessary shrinking (to reduce the total cost), update
maxito capture the maximum length of a valid substring found so far.
The function equalSubstring iterates through the strings s and t, adjusting the window size as described, and returns maxi, representing the length of the longest substring where the total cost of making characters equal does not exceed maxCost.
Analysis
Time Complexity: O(N)
The solution involves a single pass through the strings
sandtwith the sliding window, ensuring linear time complexity relative to the length of the strings.
Space Complexity: O(1)
Constant space is utilized, as the solution employs a minimal number of variables (
left,right,diff,maxi) to manage the window’s boundaries and compute the total cost within it. The space required does not scale with the size of the input strings.
def equalSubstring(self, s: str, t: str, maxCost: int) -> int:
n = len(s)
left = right = 0
diff = maxi = 0
# Function to calculate the cost of making characters at position i equal
get_diff = lambda i: abs(ord(s[i]) - ord(t[i]))
while right < n:
# Expansion: Include the cost of the new character
diff += get_diff(right)
right += 1
# Shrinking: Reduce the window size if total cost exceeds maxCost
while left < right and diff > maxCost:
diff -= get_diff(left)
left += 1
# Logic: Update the maximum length found
maxi = max(maxi, right - left)
return maxi
1658. Minimum Operations to Reduce X to Zero (Medium)¶
Solution
To find the shortest required operations that sum up to x from both ends is to find the longest subarray that sums up to total - x.
This challenge involves determining the minimum number of operations needed to reduce the sum of all elements in the array nums to a specific target value x. An operation is defined as removing an element from either the beginning or the end of the array. The solution employs a sliding window approach to find the longest subarray whose sum equals sum(nums) - x, which indirectly gives us the smallest number of elements to remove.
The key insight is to invert the problem: instead of directly finding the elements to remove, we identify the largest contiguous subarray with a total sum of sum(nums) - x. The length of the array minus the length of this subarray gives the minimum number of operations required.
- Expansion:
Traverse the array with a sliding window, incrementing
totalby each element included in the window as therightpointer advances.
- Shrinking:
If the
totalexceedsneeded(the sum required for the subarray), shrink the window from the left by decrementingtotalwith the value of the element atleftand incrementingleft.
- Logic:
When the
totalmatchesneeded, updatemaxiwith the maximum length of such a subarray found so far.
If a valid subarray is found (maxi is not zero), the minimum operations required are calculated as the total array length minus the length of this subarray. If no such subarray exists, return -1.
Analysis
Time Complexity: O(N)
The solution involves a single pass through
numswith the sliding window, ensuring linear time complexity as each element is considered exactly once for inclusion and possible removal from the total sum calculation.
Space Complexity: O(1)
Constant space is required, as the algorithm utilizes a fixed number of variables (
left,right,total,maxi) to manage the window and track the sum within it, independent of the size of the input array.
def minOperations(self, nums: List[int], x: int) -> int:
n = len(nums)
needed = sum(nums) - x
if needed == 0:
return n
left = right = 0
total = 0
maxi = 0
while right < n:
# Expansion
total += nums[right]
right += 1
# Shrinking
while left < right and total > needed:
total -= nums[left]
left += 1
# Logic
if total == needed:
maxi = max(maxi, right - left)
return n - maxi if maxi != 0 else -1
978. Longest Turbulent Subarray (Medium)¶
Solution
The objective is to find the length of the longest turbulent subarray in a given array arr. A turbulent subarray alternates between elements being strictly greater than and then less than, or vice versa, the adjacent elements. This problem is effectively tackled using a sliding window approach, complemented by a mechanism to dynamically assess the turbulence condition of the current window.
The solution iterates through arr, adjusting the window to encapsulate the longest sequence meeting the turbulent criteria. A helper function is_turbulent is employed to evaluate whether the current window’s expansion maintains the turbulent pattern.
- Initialization:
Start with a window of size 2 (
left = 0,right = 1) and assess its turbulence. Handle the case wheren == 1by immediately returning 1.
- Expansion:
Expand the window by moving the
rightpointer forward, ensuring each subsequent element alternates in comparison (less than or greater than) to the previous element, as dictated by the turbulent pattern.
- Logic:
After each potential expansion, update
maxito capture the maximum length of a turbulent subarray found so far.
- Shrinking:
Prepare for the next potential turbulent subarray by setting
leftto one position behindrightto maintain at least one element in the window that adheres to the turbulence criteria. Resetturbulencyto evaluate the turbulence pattern anew. If two consecutive elements are equal, adjustleftandrightto skip these elements, as they break the turbulent pattern.
The function maxTurbulenceSize returns maxi, indicating the length of the longest turbulent subarray identified in arr.
Analysis
Time Complexity: O(N)
The solution involves iterating through the array
arronce, with each element being evaluated for its contribution to the turbulent subarray. Adjustments to the window are performed in constant time, ensuring linear time complexity.
Space Complexity: O(1)
Constant space is used, as the algorithm employs a minimal number of variables (
left,right,maxi, andturbulency) to manage the window’s boundaries and track the longest turbulent subarray length.
def maxTurbulenceSize(self, arr: List[int]) -> int:
n = len(arr)
if n == 1:
return 1
left, right = 0, 1
turbulency = None
maxi = 0
def is_turbulent():
nonlocal turbulency
if turbulency is None:
turbulency = "lt" if arr[right - 1] < arr[right] else turbulency
turbulency = "gt" if arr[right - 1] > arr[right] else turbulency
return arr[right - 1] != arr[right]
elif turbulency == "lt":
turbulency = "gt"
return arr[right - 1] > arr[right]
else:
turbulency = "lt"
return arr[right - 1] < arr[right]
while right < n:
# Expansion
while right < n and is_turbulent():
right += 1
# Logic
maxi = max(maxi, right - left)
# Shrinking
turbulency = None
left = right - 1
if right < n and arr[left] == arr[right]:
left += 1
right += 1
return maxi
2401. Longest Nice Subarray (Medium)¶
Solution
The challenge is to find the length of the longest “nice” subarray within a given array nums. A subarray is considered “nice” if the bitwise OR of all its elements does not contain any overlapping set bits, meaning no two elements share a set bit in the same position. This solution employs a sliding window technique, utilizing bitwise operations to efficiently track the aggregate OR (current_or) of elements within the current window and dynamically adjust the window to maximize its “niceness”.
- Expansion:
Increment the
rightpointer to include new elements in the window, updatingcurrent_orwith the bitwise OR of the current elements. The expansion continues until adding another element would causecurrent_orto have overlapping set bits with the new element.
- Logic:
After each valid expansion, update
maxito capture the maximum length of the “nice” subarray found so far, calculated asright - left.
- Shrinking:
If the next element to be included shares a set bit with
current_or(indicating the subarray would no longer be “nice”), shrink the window from the left by removing elements one by one. Adjustcurrent_orby performing a bitwise XOR with the removed element to unset the bits contributed by that element.
The function longestNiceSubarray iterates through nums, adjusting the window size as described, and returns maxi, representing the length of the longest “nice” subarray found.
Analysis
Time Complexity: O(N)
The solution involves iterating through the array
numsonce with the sliding window, expanding and shrinking based on the bitwise criteria. Each element is considered exactly once for inclusion in the window, ensuring linear time complexity.
Space Complexity: O(1)
Constant space is utilized, as the solution employs a minimal number of variables (
left,right,current_or,maxi) to manage the window’s boundaries and compute the aggregate bitwise OR within it.
def longestNiceSubarray(self, nums: List[int]) -> int:
n = len(nums)
left = right = 0
current_or = maxi = 0
while right < n:
# Expansion
while right < n and current_or & nums[right] == 0:
current_or |= nums[right]
right += 1
# Logic
maxi = max(maxi, right - left)
# Shrinking
while left < right and right < n and current_or & nums[right] != 0:
current_or ^= nums[left]
left += 1
return maxi