问题描述
696.计数二进制子串
给定一个字符串 s,计算具有相同数量0和1的非空(连续)子字符串的数量,并且这些子字符串中的所有0和所有1都是组合在一起的。
重复出现的子串要计算它们出现的次数。
示例 1 :
输入: "00110011"
输出: 6
解释: 有6个子串具有相同数量的连续1和0:“0011”,“01”,“1100”,“10”,“0011” 和 “01”。
请注意,一些重复出现的子串要计算它们出现的次数。
另外,“00110011”不是有效的子串,因为所有的0(和1)没有组合在一起。
示例 2 :
输入: "10101"
输出: 4
解释: 有4个子串:“10”,“01”,“10”,“01”,它们具有相同数量的连续1和0。
注意:
- s.length 在1到50,000之间。
- s 只包含“0”或“1”字符。
题解
种子搜索
每找到一对0和1,就向两边延伸
比如"00110011",
第一次搜索到"01",两边延伸到"0011",
第二次搜索到"10",两边延伸到"1100",
第三次搜索到"01",两边延伸到"0011",
一共6个
class Solution {
public int countBinarySubstrings(String s) {
int len = s.length(),l,r;
int cut = 0;
for (int i = 0; i < len - 1; i++) {
char c1 = s.charAt(i), c2 = s.charAt(i + 1);
if (c1 != c2) {
cut ++;
l = i - 1;
r = i + 2;
while (l >= 0 && r < len && s.charAt(l) == c1 && s.charAt(r) == c2) {
cut++;
l --;
r ++;
}
}
}
return cut;
}
}
分割字符
将字符串分割成0和1的连续子串,逐次匹配
比如"00110011"分割成{“00”,“11”,“00”,“11”},依次两两匹配,
“00"和"11"可组成2个01连续子字符串"01"和"0011”,
“11"和"00"可组成2个01连续子字符串"10"和"1100”,
“00"和"11"可组成2个01连续子字符串"01"和"0011”,
一共6个。
class Solution {
public int countBinarySubstrings(String s) {
List<Integer> list = new ArrayList<Integer>();
int len = s.length(), i = 0;
while (i < len) {
char c = s.charAt(i++);
int cut = 1;
while (i < len && s.charAt(i) == c) {
i++;
cut++;
}
list.add(cut);
}
i = 1;
int cut = 0;
while (i < list.size()) {
cut += Math.min(list.get(i), list.get(i++ - 1));
}
return cut;
}
}
左右迭代
比如"00110011",
第一次左子串为"",右子串为"00",按照两边最小长度匹配只有0个’01连续子串’,
第二次左子串为"00",右子串为"11",按照两边最小长度匹配只有2个’01连续子串’,
第三次左子串为"11",右子串为"00",按照两边最小长度匹配只有2个’01连续子串’,
第一次左子串为"00",右子串为"11",按照两边最小长度匹配只有2个’01连续子串’,
class Solution {
public int countBinarySubstrings(String s) {
int len = s.length(), cut = 0, subLeftLen = 0, subRightLen = 1;
for (int i = 1; i < len; i++) {
if (s.charAt(i) == s.charAt(i - 1)) {
subRightLen ++;
} else {
cut += Math.min(subLeftLen, subRightLen);
subLeftLen = subRightLen;
subRightLen = 1;
}
}
cut += Math.min(subLeftLen, subRightLen);
return cut;
}
}