Given a binary string s
, you can split s
into 3 non-empty strings s1
, s2
, and s3
where s1 + s2 + s3 = s
.
Return the number of ways s
can be split such that the number of ones is the same in s1
, s2
, and s3
. Since the answer may be too large, return it modulo 109 + 7
.
Example 1:
Input: s = "10101" Output: 4 Explanation: There are four ways to split s in 3 parts where each part contain the same number of letters '1'. "1|010|1" "1|01|01" "10|10|1" "10|1|01"
Example 2:
Input: s = "1001" Output: 0
Example 3:
Input: s = "0000" Output: 3 Explanation: There are three ways to split s in 3 parts. "0|0|00" "0|00|0" "00|0|0"
Constraints:
3 <= s.length <= 105
s[i]
is either '0'
or '1'
.This problem asks to find the number of ways to split a binary string s
into three non-empty substrings s1
, s2
, and s3
such that each substring contains the same number of '1's.
The solution uses a counting approach with several optimizations:
Count '1's: It first counts the total number of '1's in the string. If this count is not divisible by 3, it's impossible to split the string as required, so it returns 0.
Handle the case of no '1's: If there are no '1's, any split into three non-empty substrings satisfies the condition. The number of ways to do this is the number of ways to choose two split points among n-1
possible positions, which is given by the combination formula (n-1) choose 2
= (n-1)(n-2)/2
.
Find Split Points: If there are '1's, the code calculates the number of '1's per substring (cnt
). It then uses a helper function find(x)
to find the indices where the cumulative sum of '1's reaches x
, 2x
, etc. find(x)
returns the index of the rightmost character that contributes to the cumulative sum.
Calculate the Number of Ways: Let's say i1
and i2
are the minimum and maximum indices (exclusive) where the first substring can end, having cnt
ones. Similarly, j1
and j2
are the minimum and maximum indices for the end of the second substring. The number of ways to split the string is then (i2 - i1) * (j2 - j1)
, representing the choices for the first and second split points.
Modulo Operation: The final result is taken modulo 10^9 + 7
to handle potential large values.
Time Complexity: O(n), where n is the length of the string. The string is traversed a constant number of times. The find
function has a time complexity of O(n) in the worst case, but it's called a constant number of times.
Space Complexity: O(1). The algorithm uses a constant amount of extra space.
The code implementations below follow the described approach:
class Solution:
def numWays(self, s: str) -> int:
# ... (code as provided in the original response) ...
class Solution {
// ... (code as provided in the original response) ...
}
class Solution {
public:
// ... (code as provided in the original response) ...
};
func numWays(s string) int {
// ... (code as provided in the original response) ...
}
All the code snippets above implement the same algorithm, differing only in syntax and specific language features. They all achieve the same time and space complexity.