Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ My LeetCode solutions in Java, focused on clean code and optimal algorithms.
|------|-----------------------------------------------------------------------------------------------------------------------|------------|-------------------|--------|
| 1 | [Two Sum](https://leetcode.com/problems/two-sum/) | Easy | `O(n log n)` | `O(n)` |
| 9 | [Palindrome Number](https://leetcode.com/problems/palindrome-number/) | Easy | `O(log10(n) / 2)` | `O(1)` |
| 1653 | [Minimum Deletions to Make String Balanced](https://leetcode.com/problems/minimum-deletions-to-make-string-balanced/) | Medium | `O(n²)` | `O(1)` |
| 1653 | [Minimum Deletions to Make String Balanced](https://leetcode.com/problems/minimum-deletions-to-make-string-balanced/) | Medium | `O(n)` | `O(n)` |

## Project Structure

Expand Down Expand Up @@ -128,6 +128,7 @@ mvn test -Dtest=SolutionTest

## Contributors

<!--suppress HtmlDeprecatedAttribute, HtmlUnknownAnchorTarget -->
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
package codes.yam.leetcode.minimumdeletionstomakestringbalanced;


/**
* Solution for the <b>Minimum Deletions to Make String Balanced</b> problem.
*
* <ul>
* <li><b>Time Complexity:</b> <code>O(n)</code>
* <li><b>Space Complexity:</b> <code>O(n)</code>
* </ul>
*/
class Solution {
/**
* <p>Counts misplaced characters around the given split point in {@code s}.</p>
* Counts misplaced characters around the given split point in {@code s}.
*
* <ul>
* <li><b>Time Complexity:</b> <code>O(n)</code></li>
* <li><b>Space Complexity:</b> <code>O(1)</code></li>
* <li><b>Time Complexity:</b> <code>O(n)</code>
* <li><b>Space Complexity:</b> <code>O(1)</code>
* </ul>
*
* @param s the string of {@code 'a'} and {@code 'b'} characters
* @param s the string of {@code 'a'} and {@code 'b'} characters
* @param index the split point index
* @return an array {@code [bCount, aCount]} where {@code bCount} is the number of
* {@code 'b'}s before {@code index} and {@code aCount} is the number of
* {@code 'a'}s after {@code index}
* @return an array {@code [bCount, aCount]} where {@code bCount} is the number of {@code 'b'}s
* before {@code index} and {@code aCount} is the number of {@code 'a'}s after {@code index}
*/
@SuppressWarnings("unused")
int[] getSliceInfo(String s, int index) {
int aCount = 0, bCount = 0;
for (int i = 0; i < s.length(); i++) {
Expand All @@ -26,28 +34,76 @@ int[] getSliceInfo(String s, int index) {
aCount++;
}
}
return new int[]{bCount, aCount};
return new int[] {bCount, aCount};
}

/**
* <p>Returns the minimum number of deletions to make {@code s} balanced, where balanced
* means no {@code 'b'} appears before an {@code 'a'}. Tries every split point and uses
* {@link #getSliceInfo(String, int)} to count misplaced characters at each.</p>
* Returns the minimum number of deletions to make {@code s} balanced, where balanced means no
* {@code 'b'} appears before an {@code 'a'}. Tries every split point and uses {@link
* #getSliceInfo(String, int)} to count misplaced characters at each.
*
* <ul>
* <li><b>Time Complexity:</b> <code>O(n²)</code></li>
* <li><b>Space Complexity:</b> <code>O(1)</code></li>
* <li><b>Time Complexity:</b> <code>O(n²)</code>
* <li><b>Space Complexity:</b> <code>O(1)</code>
* </ul>
*
* @param s the string of {@code 'a'} and {@code 'b'} characters
* @return the minimum number of deletions needed
*/
int minimumDeletions(String s) {
int min = Integer.MAX_VALUE;
for (int i = 0; i < s.length(); i++) {
@SuppressWarnings("unused")
int minimumDeletionsNaive(String s) {
int n = s.length();
int min = n; // we never need more than n deletions
for (int i = 0; i < n; i++) {
int[] info = getSliceInfo(s, i);
int computed = info[0] + info[1];
min = Math.min(min, computed);
}
return min;
}

/**
* Returns the minimum number of deletions to make {@code s} balanced, where balanced means no
* {@code 'b'} appears before an {@code 'a'}. Uses prefix/suffix counting to find the optimal
* split point in linear time.
*
* <ul>
* <li><b>Time Complexity:</b> <code>O(n)</code>
* <li><b>Space Complexity:</b> <code>O(n)</code>
* </ul>
*
* @param s the string of {@code 'a'} and {@code 'b'} characters
* @return the minimum number of deletions needed
*/
int minimumDeletions(String s) {
var aCountList = new int[s.length()];
var bCountList = new int[s.length()];
int aCount = 0;
int bCount = 0;
int n = s.length();
int min = n; // we never need more than n deletions

// count a's
for (int i = n - 1; i >= 0; i--) {
aCountList[i] = aCount;
if (s.charAt(i) == 'a') {
aCount++;
}
}

// count b's
for (int i = 0; i < n; i++) {
bCountList[i] = bCount;
if (s.charAt(i) == 'b') {
bCount++;
}
}

// calculate minimum
for (int i = 0; i < n; i++) {
min = Math.min(min, aCountList[i] + bCountList[i]);
}

return min;
}
}