给定一个二进制字符串 s
和两个整数 num1
和 num2
。num1
和 num2
为互质。
比率子串 是 s 的子串,其中子串中 0
的数量与 1
的数量之比正好是 num1 : num2
。
- 例如,如果
num1 = 2
和num2 = 3
,那么"01011"
和"1110000111"
是比率子串,而"11000"
不是。
返回 s
的 非空 比率子串的个数。
注意:
- 子串 是字符串中连续的字符序列。
- 如果
gcd(x, y) == 1
,则x
和y
为 互质,其中gcd(x, y)
为x
和y
的最大公约数。
示例 1:
输入: s = "0110011", num1 = 1, num2 = 2 输出: 4 解释: 有 4 个非空的比率子串。 - 子字符串 s[0..2]: "0110011"。它包含一个 0 和两个 1。比例是 1:2。 - 子字符串 s[1..4]: "0110011"。它包含一个 0 和两个 1。比例是 1:2。 - 子字符串 s[4..6]: "0110011"。它包含一个 0 和两个 1。比例是 1:2。 - 子字符串 s[1..6]: "0110011"。它包含两个 0 和四个 1。比例是 2:4 == 1:2。 它可以显示没有更多的比率子串。
示例 2:
输入: s = "10101", num1 = 3, num2 = 1 输出: 0 解释: s 没有比率子串,返回 0。
提示:
1 <= s.length <= 10^5
1 <= num1, num2 <= s.length
num1
和num2
互质。
提示 1
Let Func(i) denote the number of 0’s in the prefix [0…i]. We want to find the number of pairs of indices L and R such that Func(R) - Func(L) : R - L - Func(R) + Func(L) = num1 : num2.
提示 2
It is better to simplify the formula.
提示 3
Func(R) * (num1 + num2) - R * num1 = Func(L) * (num1 + num2) - L * num1.
提示 4
Iterate from left to right and use a hash map to count the number of indices having the same value for the above formula.
解法1:前缀和 + 哈希表
presum[ i ] = sum (nums[0..i]), presum[i] 表示 nums[0..i] 中1的个数。
i < j
presum[ j ] - presum[ i ] 表示 nums[i + 1...j] 中 1 的个数,j - i 表示 nums[i + 1...j] 的元素个数,
j - i - (presum[j] - presum[i]) , 即 j - presum[j] - i - presum[i] 表示 nums[i + 1...j] 中 0 的个数。
j - i - (presum[j] - presum[i]) : presum[j] - presum[i] == num1: num2, 转换成
( j - i - presum[j] + presum[i] ) * num2 == (presum[j] - presum[i]) * num1 , 即
presum[j] * (num1 + num2) - j * num2 == presum[i] * (num1 + num2) - i * num2
我们枚举 j ,在哈希表中 找到符合要求的 i 的个数,累加答案。
Java版:
class Solution {
public long fixedRatio(String s, int num1, int num2) {
long presum = 0;
long ans = 0;
Map<Long, Integer> map = new HashMap<>();
map.put((long) num2, 1);
for (int i = 0; i < s.length(); i++) {
presum += s.charAt(i) == '0' ? 0 : 1;
long key = presum * (num1 + num2) - i * num2;
if (map.containsKey(key)) {
ans += map.get(key);
}
map.merge(key, 1, Integer::sum);
}
return ans;
}
}
Python3版:
class Solution:
def fixedRatio(self, s: str, num1: int, num2: int) -> int:
ans = 0
presum = 0
dic = {num2: 1}
for i, c in enumerate(s):
presum += 1 if c == '1' else 0
key = presum * (num1 + num2) - i * num2
ans += dic[key] if key in dic else 0
dic[key] = 1 if key not in dic else dic[key] + 1
return ans
复杂度分析
- 时间复杂度:O(n),其中 n 是 字符串 s 的长度。需要遍历 s 一次计算前缀和,对于每个元素,更新前缀和、更新答案与操作哈希表的时间都是 O(1)。
- 空间复杂度:O(n),其中 n 是 字符串 s 的长度。哈希表的空间是 O(n)。