题目描述
给定一个字符串s
,计算具有相同数量0
和1
的非空(连续)子字符串的数量,并且这些子字符串中的所有0
和1
都是组合在一起的。
重复出现的子串要计算它们出现的次数。
示例1:
输入: s = “00110011”
输出: 6
解释: 有6个子串具有相同数量的连续1和0:“0011”,“01”,“1100”,“10”,“0011”和“01”
注意: 一些重复出现的子串要计算它们出现的次数。另外,“00110011”不是有效的子串,因为所有的0(和1)没有组合在一起。
示例2:
输入: s = “10101”
输出: 4
解释: 有4个子串:“10”,“01”,“10”,“01”,它们具有相同数量的连续1和0。
注意:
s.length
在1
到50,000
之间;s
只包含“0”或“1”字符
思路分析
题目难度为简单 ,这道题目让我想起了电路中的跳变沿,所以也采用跳变沿检测 + 两边延伸计数 的方法来解题:
- 首先需要检测出
0 -> 1
或1 -> 0
的字符所处位置; - 其次,采用“双指针法”来检测两边相同字符的长度,这个长度就是此跳变沿所涵盖的具有相同数量
0
和1
的非空(连续)子字符串的数量。
这里我们需要设置两个指针,即leftIndex, rightIndex
,对于步骤1 跳变沿检测,我们以while(rightIndex + 1 < s.length())
为循环条件,判断s.charAt(rightIndex) != s.charAt(rightIndex + 1)
来判断是否为跳变沿;对于步骤2,我们在检测到跳变沿后,令leftIndex == rightIndex++
,此时两指针分别位于跳变两端,分别向各自方向遍历,检测符合题意的子串数量。
解题代码
public static int solution(String s) {
int res = 0;
int leftIndex = 0, rightIndex = 0;
while(rightIndex+1 < s.length()){
if(s.charAt(rightIndex) == s.charAt(rightIndex + 1))
rightIndex++;
else{
res++;
leftIndex = rightIndex++;
while((leftIndex - 1)>=0 && (rightIndex+1)<s.length()
&& (s.charAt(leftIndex)==s.charAt(--leftIndex)
&& s.charAt(rightIndex)==s.charAt(++rightIndex)) )
res++;
}
}
return res;
}
复杂度分析
我们设n
为s
的字符串长度
时间复杂度: 我们会字符串进行大于等于一次,最多两次的字符串访问,故时间复杂度为O(n)
;
空间复杂度: 没有借助辅助容器,故空间复杂度为O(1)
;
Github源码
完整可运行文件请访问GitHub。