Problem
Given a binary string s, count all substrings that contain more 1s than 0s.
Example
Input:
s = "011"
Output:
4
Explanation
The valid substrings are:
"011""1""11""1"
Brute Force Approach
Generate every possible substring and count the number of 0s and 1s.
for every starting index
for every ending index
count 0 and 1
if (ones > zeros)
answer++
Complexity
Time:
O(N³)(orO(N²)with prefix counts)Space:
O(1)
This approach is too slow for N = 60000.
Optimized Idea
Instead of counting zeros and ones separately for every substring, convert the problem into a prefix sum problem.
Step 1: Convert Characters
Replace:
1 → +1
0 → -1
Example
0110
becomes
-1 +1 +1 -1
Step 2: Prefix Sum
Create prefix sums.
Prefix[0] = 0
Prefix[i] = sum of first i characters
Example
String : 0 1 1
Value : -1 +1 +1
Prefix array:
Index : 0 1 2 3
Value : 0 -1 0 1
Step 3: Substring Sum
For a substring:
l...r
its sum is:
Prefix[r + 1] - Prefix[l]
If:
sum > 0
then:
ones > zeros
Therefore:
Prefix[r + 1] > Prefix[l]
So, for every current prefix sum, we only need to know:
How many previous prefix sums are smaller than the current prefix sum?
This becomes the entire problem.
Why Fenwick Tree?
Suppose the current prefix sum is:
5
We need to count how many previously seen prefix sums are:
-3
-2
0
1
2
4
A Fenwick Tree can efficiently answer:
How many values are smaller than x?
in:
O(log N)
time.
Coordinate Compression
Prefix sums can range from:
-N to +N
For:
N = 60000
the range becomes:
-60000 ... 60000
Instead of creating a huge Fenwick Tree, compress the values.
Example
Original values:
-5
2
8
0
After sorting:
-5
0
2
8
Assign ranks:
-5 → 1
0 → 2
2 → 3
8 → 4
The Fenwick Tree stores only these ranks.
Code Explanation
Solution Class
class Solution {
This is the main solution class.
Fenwick Tree
class Fenwick {
The Fenwick Tree supports:
Update
Prefix query
Variables
int[] bit;
int n;
bitstores frequencies.nis the size of the tree.
Constructor
Fenwick(int n) {
this.n = n;
bit = new int[n + 2];
}
Creates the Fenwick Tree.
Update
void update(int idx, int val) {
while (idx <= n) {
bit[idx] += val;
idx += idx & -idx;
}
}
Adds one occurrence of a prefix sum.
Example
Current prefix sum:
3
update(rank(3), 1);
Now the Fenwick Tree remembers that prefix sum 3 has appeared once.
Query
int query(int idx) {
int sum = 0;
while (idx > 0) {
sum += bit[idx];
idx -= idx & -idx;
}
return sum;
}
Returns the number of prefix sums whose rank is less than or equal to idx.
Build Prefix Array
int[] pref = new int[n + 1];
pref[0] = 0;
The prefix sum always starts with zero.
Build Prefix Sums
for (int i = 1; i <= n; i++) {
pref[i] = pref[i - 1] + (s.charAt(i - 1) == '1' ? 1 : -1);
}
If the current character is:
1
add:
+1
Otherwise, add:
-1
Example
For:
011

Join the conversation! Your thoughts help the community grow.