題面
遊遊的好串
遊遊有一個只包含'0'和'1'的字串,他想知道這個字串有多少個好子串?
一個字串如果是"好串",那麼該字串的所有字首,'0'的數量嚴格大於'1'的數量。
輸入
輸入一個只包含'0'和'1'的字串,長度不超過100000。
輸出
輸出一個整數,代表答案。
示例
輸入例子:
100
輸出例子:
3
例子說明:
子區間 [2, 2], [2, 3], [3, 3] 組成的子串都是一個好串。
輸入例子:
10010
輸出例子:
6
例子說明:
子區間 [2, 2], [3, 3], [2, 3], [2, 4], [2, 5], [5, 5] 組成的子串是一個好串。
核心思想
滑動視窗
首先要明確的一點時視窗滑動的過程本身就是字首
那麼視窗兩端 l,r 表示 從 l 開始,以 r 結尾的所有子串滿足要求的有多少個
這一步操作就是選擇了子串 [l,r] [l+1,r]....[r,r]
以 10010 為例
當視窗來到 l = 2, r = 4 時(下標從1開始)視窗串為 001
我們執行 res += (r - l + 1); 這一計算的意義是什麼?
我們認為 001, 01, 1 這樣的字串都滿足要求 但事實上 01, 1 是需要剔除的
分析後可以發現是因為有1的存在
分為兩種情況
- 以 1 開頭的子串, 數量為視窗內 1 的個數
- 第二種就是上面例子中 01 這樣的 前面0的個數太少 這樣的有多少個?同樣是 1 的個數
我們換一個例子 0010101,視窗會來到 l = 1, r = 7, cnt1 = 3(視窗內1的個數)
010101, 10101
0101, 101
01, 1
這些都是不滿足的 也就是1的個數乘2
程式碼
import java.util.*;
class Main {
static final int MAXN = (int) (1e5 + 10);
static char[] chs = new char[MAXN];
static long res = 0;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
int n = s.length();
for(int i = 1; i <= n; i++){
chs[i] = s.charAt(i - 1);
}
int cnt1 = 0, cnt0 = 0;
for(int l = 1, r = 1; r <= n; r++){
if(chs[r] == '0')
cnt0++;
else{
cnt1++;
}
while(cnt1 >= cnt0 && l <= r){
if(chs[l] == '0')
cnt0--;
else
cnt1--;
l++;
}
res += (r - l + 1);
res -= 2L * cnt1;
}
System.out.println(res);
}
}