Lexicographically Minimum String After Removing Stars
MedPrompt
You are given a string s. It may contain any number of '*' characters. Your task is to remove all '*' characters.
While there is a '*', do the following operation:
- Delete the leftmost
'*'and the smallest non-'*'character to its left. If there are several smallest characters, you can delete any of them.
Return the lexicographically smallest resulting string after removing all '*' characters.
Example 1:
Input: s = "aaba*"
Output: "aab"
Explanation:
We should delete one of the 'a' characters with '*'. If we choose s[3], s becomes the lexicographically smallest.
Example 2:
Input: s = "abc"
Output: "abc"
Explanation:
There is no '*' in the string.
Constraints:
1 <= s.length <= 105sconsists only of lowercase English letters and'*'.- The input is generated such that it is possible to delete all
'*'characters.
Approaches
3 approaches with complexity analysis and trade-offs.
This approach directly simulates the process described in the problem. It repeatedly finds the leftmost star, identifies the character to be removed based on the greedy strategy, and reconstructs the string. This process continues until no stars are left.
Algorithm
- Convert the input string
sto a mutableStringBuilder. - Loop as long as a
'*'character exists in theStringBuilder.- Find the index of the leftmost
'*'. Let this bestarIndex. - If no star is found, exit the loop.
- Find the smallest character in the substring to the left of the star (
0tostarIndex - 1). - Find the rightmost index (
removeIndex) of this smallest character in the same left-side substring. - Delete the character at
starIndexfirst, then the character atremoveIndex.
- Find the index of the leftmost
- Convert the
StringBuilderback to a string and return it.
Walkthrough
In this brute-force method, we use a mutable string representation, like Java's StringBuilder, to allow for efficient character deletions. We enter a loop that continues as long as there are '*' characters in the string. In each iteration, we locate the first '*'. Then, we scan all characters to its left to determine the smallest character. To get the lexicographically smallest final string, we must remove the rightmost occurrence of this smallest character. So, we perform a reverse scan from the star's position to find its index. Finally, we delete both the star and the identified character. This is repeated until all stars are processed.
class Solution { public String clearStars(String s) { StringBuilder sb = new StringBuilder(s); while (true) { int starIndex = sb.indexOf("*"); if (starIndex == -1) { break; } char smallestChar = Character.MAX_VALUE; int removeIndex = -1; // Find the smallest character to the left of the star for (int i = 0; i < starIndex; i++) { if (sb.charAt(i) != '*') { smallestChar = (char) Math.min(smallestChar, sb.charAt(i)); } } // Find the rightmost occurrence of that smallest character for (int i = starIndex - 1; i >= 0; i--) { if (sb.charAt(i) == smallestChar) { removeIndex = i; break; } } // Delete star first (larger index) to not affect smaller index sb.deleteCharAt(starIndex); if (removeIndex != -1) { sb.deleteCharAt(removeIndex); } } return sb.toString(); }}Complexity
Time
O(N^2), where N is the length of the string. In each of the O(N) iterations (one for each star), finding the star, the smallest character, and its position takes O(N) time. Deletion in a `StringBuilder` also takes O(N).
Space
O(N), where N is the length of the string, for storing the `StringBuilder`.
Trade-offs
Pros
Conceptually simple and easy to follow the problem's description.
Cons
Highly inefficient due to repeated scanning and modification of the string.
Will likely result in a 'Time Limit Exceeded' error for large inputs.
Solutions
Solution
public class Solution { public string ClearStars(string s) { int n = s.Length; List < int > [] g = new List < int > [26]; for (int i = 0; i < 26; i++) { g[i] = new List < int > (); } bool[] rem = new bool[n]; for (int i = 0; i < n; i++) { char ch = s[i]; if (ch == '*') { rem[i] = true; for (int j = 0; j < 26; j++) { if (g[j].Count > 0) { int idx = g[j][g[j].Count - 1]; g[j].RemoveAt(g[j].Count - 1); rem[idx] = true; break; } } } else { g[ch - 'a'].Add(i); } } var ans = new System.Text.StringBuilder(); for (int i = 0; i < n; i++) { if (!rem[i]) { ans.Append(s[i]); } } return ans.ToString(); }}Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.