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
59 changes: 59 additions & 0 deletions problems/3714-longest-balanced-substring-ii/analysis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# 3714. Longest Balanced Substring II

[LeetCode Link](https://leetcode.com/problems/longest-balanced-substring-ii/)

Difficulty: Medium
Topics: Hash Table, String, Prefix Sum
Acceptance Rate: 26.6%

## Hints

### Hint 1

Think about what "balanced" means in terms of character counts. A substring is balanced if every distinct character in it appears the same number of times. Consider how prefix sums of character frequencies might help you detect equal-count substrings efficiently.

### Hint 2

The classic trick for "equal frequency" problems is to track **differences** between character counts rather than absolute counts. If the difference between counts is the same at two positions, the substring between those positions has equal increments for the relevant characters. But be careful — this only handles the case where **all three** characters appear equally. You need to consider substrings that contain only one or two distinct characters separately.

### Hint 3

Break the problem into cases based on which characters appear in the substring:
- **Single character**: Any maximal run of one character is balanced. Just find the longest run.
- **Two characters**: For each pair like (a,b), find maximal contiguous segments that contain only those two characters, then within each segment use a prefix-difference map (`count_x - count_y`) to find the longest sub-segment where both characters appear equally.
- **Three characters**: Use a 2D prefix-difference state `(count_a - count_b, count_a - count_c)`. Store the earliest index for each state; when you see the same state again, the substring between has equal counts of all three.

The answer is the maximum across all cases.

## Approach

We split the problem into three scenarios by how many distinct characters the balanced substring contains:

**Case 1 — One distinct character:** Scan the string and track the length of consecutive runs of the same character. Any such run is balanced.

**Case 2 — Two distinct characters (3 sub-cases for pairs ab, ac, bc):** For each character pair, identify maximal contiguous segments of the string that contain only characters from that pair. Within each segment, use the prefix-difference technique: maintain a running difference `count_x - count_y` and a hash map storing the first index where each difference value was seen. When the same difference appears again, the substring between those indices has equal counts of both characters.

**Case 3 — All three characters:** Maintain running counts of a, b, c. The state is `(count_a - count_b, count_a - count_c)`. Use a hash map from state to the earliest index. When the same state recurs at index j, the substring from the stored index+1 to j has equal counts of all three characters.

The final answer is the maximum length found across all cases.

### Example walkthrough: s = "abbac"

- Prefix counts at each position: a=[1,1,1,2,2], b=[0,1,2,2,2], c=[0,0,0,0,1]
- For the all-three case, states (a-b, a-c): index 0→(1,-1), 1→(0,1), 2→(-1,1), 3→(0,2), 4→(1,1). No repeated states, so no all-three balanced substring.
- For pair (a,b): segment "abba" (indices 0–3) has only a,b. Differences [1,0,-1,0]. Difference 0 first at index 1, recurs at index 3 → length 2. But also difference 0 at the start (before index 0) maps to length at index 3 = 4. So we get length 4.
- Result: 4.

## Complexity Analysis

Time Complexity: O(n) — We make a constant number of linear passes over the string.

Space Complexity: O(n) — For the hash maps storing first-occurrence indices of prefix-difference states.

## Edge Cases

- **Single character string** (e.g., "a"): The entire string is balanced. Length = 1.
- **All same characters** (e.g., "aaaa"): The entire string is balanced.
- **Two characters alternating** (e.g., "ababab"): Longest balanced substring is the full string if both have equal counts, or length n-1 otherwise.
- **No two characters have equal count in any substring longer than 1**: The answer is 1 (each single character is trivially balanced).
- **Entire string is balanced with all three characters**: The answer is the full string length.
64 changes: 64 additions & 0 deletions problems/3714-longest-balanced-substring-ii/problem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
number: "3714"
frontend_id: "3714"
title: "Longest Balanced Substring II"
slug: "longest-balanced-substring-ii"
difficulty: "Medium"
topics:
- "Hash Table"
- "String"
- "Prefix Sum"
acceptance_rate: 2663.3
is_premium: false
created_at: "2026-02-13T03:26:32.958422+00:00"
fetched_at: "2026-02-13T03:26:32.958422+00:00"
link: "https://leetcode.com/problems/longest-balanced-substring-ii/"
date: "2026-02-13"
---

# 3714. Longest Balanced Substring II

You are given a string `s` consisting only of the characters `'a'`, `'b'`, and `'c'`.

A **substring** of `s` is called **balanced** if all **distinct** characters in the **substring** appear the **same** number of times.

Return the **length of the longest balanced substring** of `s`.



**Example 1:**

**Input:** s = "abbac"

**Output:** 4

**Explanation:**

The longest balanced substring is `"abba"` because both distinct characters `'a'` and `'b'` each appear exactly 2 times.

**Example 2:**

**Input:** s = "aabcc"

**Output:** 3

**Explanation:**

The longest balanced substring is `"abc"` because all distinct characters `'a'`, `'b'` and `'c'` each appear exactly 1 time.

**Example 3:**

**Input:** s = "aba"

**Output:** 2

**Explanation:**

One of the longest balanced substrings is `"ab"` because both distinct characters `'a'` and `'b'` each appear exactly 1 time. Another longest balanced substring is `"ba"`.



**Constraints:**

* `1 <= s.length <= 105`
* `s` contains only the characters `'a'`, `'b'`, and `'c'`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package main

// Approach: Split into cases by number of distinct characters in the balanced substring.
// 1) Single char: longest run of one character.
// 2) Two chars: for each pair, find maximal segments with only those chars,
// then use prefix-difference technique within each segment.
// 3) All three chars: use 2D prefix-difference state (countA-countB, countA-countC).
// Time: O(n), Space: O(n)

func longestBalancedSubstring(s string) int {
n := len(s)
if n == 0 {
return 0
}
ans := 1 // single character is always balanced

// Case 1: longest run of a single character
run := 1
for i := 1; i < n; i++ {
if s[i] == s[i-1] {
run++
} else {
run = 1
}
if run > ans {
ans = run
}
}

// Case 2: two-character pairs
pairs := [][2]byte{{'a', 'b'}, {'a', 'c'}, {'b', 'c'}}
for _, pair := range pairs {
c1, c2 := pair[0], pair[1]
// Process maximal segments containing only c1 and c2
i := 0
for i < n {
if s[i] != c1 && s[i] != c2 {
i++
continue
}
// Start of a segment with only c1/c2
diff := 0 // count(c1) - count(c2)
first := map[int]int{0: i - 1}
j := i
for j < n && (s[j] == c1 || s[j] == c2) {
if s[j] == c1 {
diff++
} else {
diff--
}
if idx, ok := first[diff]; ok {
length := j - idx
if length > ans {
ans = length
}
} else {
first[diff] = j
}
j++
}
i = j
}
}

// Case 3: all three characters with equal counts
// State: (countA - countB, countA - countC)
type state struct {
ab, ac int
}
firstSeen := map[state]int{{0, 0}: -1}
var ca, cb, cc int
for i := 0; i < n; i++ {
switch s[i] {
case 'a':
ca++
case 'b':
cb++
case 'c':
cc++
}
st := state{ca - cb, ca - cc}
if idx, ok := firstSeen[st]; ok {
length := i - idx
if length > ans {
ans = length
}
} else {
firstSeen[st] = i
}
}

return ans
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import "testing"

func TestLongestBalancedSubstring(t *testing.T) {
tests := []struct {
name string
s string
expected int
}{
// Examples from the problem
{"example 1: abbac", "abbac", 4},
{"example 2: aabcc", "aabcc", 3},
{"example 3: aba", "aba", 2},
// Edge cases
{"single character", "a", 1},
{"all same character", "aaaa", 4},
{"all three equal", "abc", 3},
{"all three repeated equally", "aabbcc", 6},
{"two chars alternating", "abab", 4},
{"no balanced longer than 1", "abccc", 3},
{"entire string balanced with three chars", "abcabc", 6},
{"long single char run", "bbbbb", 5},
{"pair balanced at end", "cccab", 3},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := longestBalancedSubstring(tt.s)
if result != tt.expected {
t.Errorf("longestBalancedSubstring(%q) = %d, want %d", tt.s, result, tt.expected)
}
})
}
}