Problem
Given a string and a set of characters, return the shortest substring containing all the characters in the set. If there is no such substring, return null.
Examples
Example 1
Input: string = "figehaeci", set = {a, e, i}
Output: "aeci"
Explanation: The substring "aeci" contains all the characters {a, e, i}.
Example 2
Input: string = "figehaeci", set = {x, y, z}
Output: ""
Explanation: There is no substring in "figehaeci" that contains all the characters {x, y, z}.
Solution
Method 1 - Sliding Window
To solve the problem, we can use a sliding window approach which involves expanding and contracting the window to find the shortest possible substring that contains all the characters of the given set.
Here is the approach:
- Initialise Data Structures: Use two hash maps to store the frequency of characters in the set and the current window.
- Expand and Contract Window:
- Expand the right end of the window by moving the right pointer.
- When the window contains all characters from the set, try to make the window smaller by moving the left pointer.
- Update the length of the shortest valid window found during the process.
- Return Result: If a valid window is found, return the substring; otherwise, return
null
.
Code
Java
public class Solution {
public String shortestSubstringContainingSet(String s, Set<Character> set) {
if (s == null || set == null || set.isEmpty() || s.length() < set.size()) {
return null;
}
Map<Character, Integer> charCount = new HashMap<>();
Map<Character, Integer> windowCount = new HashMap<>();
// Initialize the character count from set
for (char c : set) {
charCount.put(c, charCount.getOrDefault(c, 0) + 1);
}
int left = 0, right = 0, minLength = Integer.MAX_VALUE, start = -1, matched = 0;
while (right < s.length()) {
char rightChar = s.charAt(right);
if (charCount.containsKey(rightChar)) {
windowCount.put(rightChar, windowCount.getOrDefault(rightChar, 0) + 1);
if (windowCount.get(rightChar).intValue() == charCount.get(rightChar).intValue()) {
matched++;
}
}
while (matched == charCount.size()) {
if (right - left + 1 < minLength) {
minLength = right - left + 1;
start = left;
}
char leftChar = s.charAt(left);
if (charCount.containsKey(leftChar)) {
if (windowCount.get(leftChar).intValue() == charCount.get(leftChar).intValue()) {
matched--;
}
windowCount.put(leftChar, windowCount.get(leftChar) - 1);
}
left++;
}
right++;
}
return start == -1 ? null : s.substring(start, start + minLength);
}
public static void main(String[] args) {
Solution solution = new Solution();
System.out.println(solution.shortestSubstringContainingSet("figehaeci", Set.of('a', 'e', 'i'))); // Output: aeci
System.out.println(solution.shortestSubstringContainingSet("figehaeci", Set.of('x', 'y', 'z'))); // Output: null
}
}
Python
class Solution:
def shortestSubstringContainingSet(self, s: str, char_set: set) -> str or None:
if not s or not char_set or len(char_set) > len(s):
return None
char_count = {char: 0 for char in char_set}
window_count = {char: 0 for char in char_set}
for char in char_set:
char_count[char] += 1
left, right = 0, 0
min_length = float('inf')
start = -1
matched = 0
while right < len(s):
right_char = s[right]
if right_char in window_count:
window_count[right_char] += 1
if window_count[right_char] == char_count[right_char]:
matched += 1
while matched == len(char_count):
if right - left + 1 < min_length:
min_length = right - left + 1
start = left
left_char = s[left]
if left_char in window_count:
if window_count[left_char] == char_count[left_char]:
matched -= 1
window_count[left_char] -= 1
left += 1
right += 1
return None if start == -1 else s[start:start + min_length]
# Example usage
solution = Solution()
print(solution.shortestSubstringContainingSet("figehaeci", {'a', 'e', 'i'})) # Output: aeci
print(solution.shortestSubstringContainingSet("figehaeci", {'x', 'y', 'z'})) # Output: None
Complexity
- ⏰ Time complexity:
O(n)
wheren
is the length of the string. The two pointers (left and right) each traverse the string once. - 🧺 Space complexity:
O(m)
wherem
is the number of unique characters in the set (for storing the frequency count in hash maps).