1、题目描述
给定一个字符串 s,计算具有相同数量 0 和 1 的非空(连续)子字符串的数量,并且这些子字符串中的所有 0 和所有 1 都是连续的。
重复出现的子串要计算它们出现的次数。
2、算法分析
本问题中对称中心只能是两个字符的中间,可以用整形序列[1, s.length() - 1]来表示回文中心的位置,那么left = i - 1, right = i 就是最中心的两个字符。
比如i = 1时left = 0, right = 1 ,就是第一个可能的满足题目要求的子串。由原字符串中第一,第二个字符构成。
所以遍历每一个回文中心的循环为for(int i = 1; i < s.length(); i++)
在循环中首先要保证,回文中心左右的两个字符char leftChar = chars[left], rightChar = chars[right];一个是0,另外一个是1。
如果都是1或者都是0,那么没有以这个为中心的符合要求的字串,后续就不用从中心向外扩展了if(leftChar == rightChar) continue;。
如果leftChar != rightChar,就以此为中心,。使用一个while循环来计数这个中心有多少个符合题意的子串。循环条件首先保证索引不越界,其次leftChar左边的字符都要和它相等,rightChar右边的字符都要和它相等。不断向外扩展就是left--; right++;注意以下几点:
①子串中具有相同数量的0和1,且出现的次数都是相同的。000111 01 1100
②00110011不是有效的子串,因为所有的1和0没有组合在一起。
③转换成字符数组的时候,注意数组的长度是1,长度范围需要是字符串的长度、
经过分析题目中的意思,接下来就好办了。可以使用中心扩展法。之前做过一题,求回文子串。
3、代码实现
public int countBinarySubstrings(String s) {
int result = 0;
char[] chars = s.toCharArray();
// 遍历分析
for(int i = 1; i < s.length(); i++){
int left = i - 1, right = i;
char leftChar = chars[left], rightChar = chars[right];
//如果相邻且相等,那么不符合题目要求继续往下找。
if(leftChar == rightChar)
continue;
// 中心向左向右扩展
while(left >= 0 && right < s.length() && chars[left] == leftChar && chars[right] == rightChar){
left--;
right++;
result++;
}
}
return result;
}