301. Remove Invalid Parentheses
Given a string s that contains parentheses and letters, remove the minimum number of invalid parentheses to make the input string valid.
Return a list of unique strings that are valid with the minimum number of removals. You may return the answer in any order.
Example 1:
Example 2:
Example 3:
Constraints:
- 1 <= s.length <= 25
- s consists of lowercase English letters and parentheses ‘(’ and ‘)’.
- There will be at most 20 parentheses in s.
From: LeetCode
Link: 301. Remove Invalid Parentheses
Solution:
Ideas:
1. Dynamic Queue and Result Resizing:
- Queue Resizing: The BFS queue is initialized with a default size and dynamically resized if more space is needed.
- Result Resizing: The result array is similarly resized to accommodate more valid strings as they are discovered.
2. Proper Memory Management:
- Freeing Strings: Each dynamically allocated string in the queue and results is properly freed once it is no longer needed.
- Clearing Visited Set: The visited set is cleared after BFS to avoid memory leaks.
3. Queue Management:
- BFS Logic: The BFS queue is processed level by level, ensuring that all possibilities are explored and that only the minimum removal solutions are considered.
- Memory Safety: All reallocations ensure that sufficient space is available, preventing buffer overflows and related errors.
4. Edge Cases:
- Empty Strings: An explicit check is added for empty or null input strings, returning an empty string as the valid output.
Code:
#define INITIAL_QUEUE_SIZE 1000
#define INITIAL_RESULT_SIZE 1000
// Define a structure for a hash table to store unique strings
typedef struct {
char *str; // Pointer to the stored string
UT_hash_handle hh; // Hash handle for uthash
} VisitedSet;
// Function to check if a given string has valid parentheses
bool isValid(char *s) {
int balance = 0;
for (int i = 0; s[i]; ++i) {
if (s[i] == '(') balance++;
if (s[i] == ')') balance--;
if (balance < 0) return false; // More closing than opening
}
return balance == 0;
}
// Function to add a string to the visited set
bool addToVisited(VisitedSet **visited, const char *str) {
VisitedSet *entry;
HASH_FIND_STR(*visited, str, entry); // Check if already present
if (!entry) {
entry = (VisitedSet *)malloc(sizeof(VisitedSet));
entry->str = strdup(str);
HASH_ADD_KEYPTR(hh, *visited, entry->str, strlen(entry->str), entry);
return true;
}
return false;
}
// Function to clear the visited set
void clearVisitedSet(VisitedSet *visited) {
VisitedSet *current_entry, *tmp;
HASH_ITER(hh, visited, current_entry, tmp) {
HASH_DEL(visited, current_entry);
free(current_entry->str);
free(current_entry);
}
}
// Function to remove invalid parentheses
char **removeInvalidParentheses(char *s, int *returnSize) {
char **result = malloc(INITIAL_RESULT_SIZE * sizeof(char *));
int resultCapacity = INITIAL_RESULT_SIZE;
*returnSize = 0;
if (!s || !*s) {
// If string is empty or NULL, return empty string as the only valid result
result[0] = strdup("");
*returnSize = 1;
return result;
}
VisitedSet *visited = NULL;
char **queue = malloc(INITIAL_QUEUE_SIZE * sizeof(char *));
int front = 0, rear = 0, queueCapacity = INITIAL_QUEUE_SIZE;
bool found = false;
// Initialize BFS
queue[rear++] = strdup(s);
addToVisited(&visited, s);
while (front < rear) {
int levelSize = rear - front;
for (int i = 0; i < levelSize; ++i) {
char *current = queue[front++];
// Check if current string is valid
if (isValid(current)) {
if (!found) {
found = true;
// Reset result since this is the first valid solution
*returnSize = 0;
}
// Add valid string to result
if (*returnSize >= resultCapacity) {
resultCapacity *= 2;
result = realloc(result, resultCapacity * sizeof(char *));
}
result[(*returnSize)++] = strdup(current);
}
// If found, skip generating further states
if (found) {
free(current);
continue;
}
// Generate new states by removing one parenthesis at a time
int len = strlen(current);
for (int j = 0; j < len; ++j) {
if (current[j] != '(' && current[j] != ')') continue;
char *next = strdup(current);
memmove(&next[j], &next[j + 1], len - j);
if (addToVisited(&visited, next)) {
// Resize queue if needed
if (rear >= queueCapacity) {
queueCapacity *= 2;
queue = realloc(queue, queueCapacity * sizeof(char *));
}
queue[rear++] = next;
} else {
free(next);
}
}
free(current);
}
// If a valid expression was found, stop further exploration
if (found) break;
}
clearVisitedSet(visited);
free(queue);
// If no valid expression found, return empty string
if (*returnSize == 0) {
result[0] = strdup("");
*returnSize = 1;
}
return result;
}
// Helper function to free the result array
void freeResults(char **results, int returnSize) {
for (int i = 0; i < returnSize; ++i) {
free(results[i]);
}
free(results);
}