Using greedy without proof
Wrong move: Locally optimal choices may fail globally.
Usually fails on: Counterexamples appear on crafted input orderings.
Fix: Verify with exchange argument or monotonic objective before committing.
Build confidence with an intuition-first walkthrough focused on greedy fundamentals.
Balanced strings are those that have an equal quantity of 'L' and 'R' characters.
Given a balanced string s, split it into some number of substrings such that:
Return the maximum number of balanced strings you can obtain.
Example 1:
Input: s = "RLRRLLRLRL" Output: 4 Explanation: s can be split into "RL", "RRLL", "RL", "RL", each substring contains same number of 'L' and 'R'.
Example 2:
Input: s = "RLRRRLLRLL" Output: 2 Explanation: s can be split into "RL", "RRRLLRLL", each substring contains same number of 'L' and 'R'. Note that s cannot be split into "RL", "RR", "RL", "LR", "LL", because the 2nd and 5th substrings are not balanced.
Example 3:
Input: s = "LLLLRRRR" Output: 1 Explanation: s can be split into "LLLLRRRR".
Constraints:
2 <= s.length <= 1000s[i] is either 'L' or 'R'.s is a balanced string.Problem summary: Balanced strings are those that have an equal quantity of 'L' and 'R' characters. Given a balanced string s, split it into some number of substrings such that: Each substring is balanced. Return the maximum number of balanced strings you can obtain.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Greedy
"RLRRLLRLRL"
"RLRRRLLRLL"
"LLLLRRRR"
split-strings-by-separator)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1221: Split a String in Balanced Strings
class Solution {
public int balancedStringSplit(String s) {
int ans = 0, l = 0;
for (char c : s.toCharArray()) {
if (c == 'L') {
++l;
} else {
--l;
}
if (l == 0) {
++ans;
}
}
return ans;
}
}
// Accepted solution for LeetCode #1221: Split a String in Balanced Strings
func balancedStringSplit(s string) int {
ans, l := 0, 0
for _, c := range s {
if c == 'L' {
l++
} else {
l--
}
if l == 0 {
ans++
}
}
return ans
}
# Accepted solution for LeetCode #1221: Split a String in Balanced Strings
class Solution:
def balancedStringSplit(self, s: str) -> int:
ans = l = 0
for c in s:
if c == 'L':
l += 1
else:
l -= 1
if l == 0:
ans += 1
return ans
// Accepted solution for LeetCode #1221: Split a String in Balanced Strings
struct Solution;
impl Solution {
fn balanced_string_split(s: String) -> i32 {
let mut l = 0;
let mut r = 0;
let mut res = 0;
for c in s.chars() {
match c {
'R' => r += 1,
'L' => l += 1,
_ => {}
}
if l == r {
res += 1;
}
}
res
}
}
#[test]
fn test() {
let s = "RLRRLLRLRL".to_string();
assert_eq!(Solution::balanced_string_split(s), 4);
let s = "RLLLLRRRLR".to_string();
assert_eq!(Solution::balanced_string_split(s), 3);
let s = "LLLLRRRR".to_string();
assert_eq!(Solution::balanced_string_split(s), 1);
}
// Accepted solution for LeetCode #1221: Split a String in Balanced Strings
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #1221: Split a String in Balanced Strings
// class Solution {
// public int balancedStringSplit(String s) {
// int ans = 0, l = 0;
// for (char c : s.toCharArray()) {
// if (c == 'L') {
// ++l;
// } else {
// --l;
// }
// if (l == 0) {
// ++ans;
// }
// }
// return ans;
// }
// }
Use this to step through a reusable interview workflow for this problem.
Try every possible combination of choices. With n items each having two states (include/exclude), the search space is 2ⁿ. Evaluating each combination takes O(n), giving O(n × 2ⁿ). The recursion stack or subset storage uses O(n) space.
Greedy algorithms typically sort the input (O(n log n)) then make a single pass (O(n)). The sort dominates. If the input is already sorted or the greedy choice can be computed without sorting, time drops to O(n). Proving greedy correctness (exchange argument) is harder than the implementation.
Review these before coding to avoid predictable interview regressions.
Wrong move: Locally optimal choices may fail globally.
Usually fails on: Counterexamples appear on crafted input orderings.
Fix: Verify with exchange argument or monotonic objective before committing.