Unit 7 Session 2 (Click for link to problem statements)
Understand what the interviewer is asking for by using test cases and questions about the problem.
- Established a set (2-3) of test cases to verify their own solution later.
- Established a set (1-2) of edge cases to verify their solution handles complexities.
- Have fully understood the problem and have no clarifying questions.
- Have you verified any Time/Space Constraints for this problem?
0
.s
is empty?
0
since there are no substrings.HAPPY CASE
Input: s = "tatooine", k = 2
Output: 2
Explanation: The longest substring is "oo" as 'o' is repeated 2 times.
Input: s = "chewbacca", k = 2
Output: 4
Explanation: The longest substring is "acca" as both 'a' and 'c' are repeated 2 times.
EDGE CASE
Input: s = "abcde", k = 2
Output: 0
Explanation: No character repeats 2 times.
Input: s = ", k = 3
Output: 0
Explanation: The string is empty, so return 0.
Match what this problem looks like to known categories of problems, e.g., Linked List or Dynamic Programming, and strategies or patterns in those categories.
For Divide and Conquer problems, we want to consider the following approaches:
Plan the solution with appropriate visualizations and pseudocode.
General Idea: Use a divide-and-conquer approach by recursively splitting the string into smaller substrings whenever a character does not meet the frequency requirement. The base case is when the substring length is less than k
.
Pseudocode:
1) Define a helper function `divide_and_conquer(s, k)`:
a) Base Case: If the length of `s` is less than `k`, return 0.
b) Create a frequency map to count the occurrences of each character in `s`.
c) For each character in `s`, if its frequency is less than `k`, split the string by this character and recursively apply `divide_and_conquer` to each part.
d) If every character in `s` meets the frequency requirement, return the length of `s`.
2) The main function `longest_substring(s, k)` will call the `divide_and_conquer` function and return the result.
k
.Implement the code to solve the algorithm.
def longest_substring(s, k):
def divide_and_conquer(s, k):
# Base case: if the length of the string is less than k, no valid substring exists
if len(s) < k:
return 0
# Create a frequency map
freq_map = {}
for char in s:
freq_map[char] = freq_map.get(char, 0) + 1
# Split string by characters that appear less than k times
for char in freq_map:
if freq_map[char] < k:
# Split by the character and recursively apply on each part
return max(divide_and_conquer(sub_str, k) for sub_str in s.split(char))
# If every character appears at least k times, the whole string is valid
return len(s)
return divide_and_conquer(s, k)
Review the code by running specific example(s) and recording values (watchlist) of your code's variables along the way.
"tatooine", k = 2
:
Evaluate the performance of your algorithm and state any strong/weak or future potential work.
Assume N
represents the length of the string s
.
O(N * log N)
in the worst case, as the string is recursively divided.O(N)
due to the recursive call stack and frequency map storage.