一、Problem
小明最近在做病毒自動檢測,他發現,在某些library 的代碼段的二進制表示中,如果包含子串並且恰好有k個1,就有可能有潛在的病毒。library的二進制表示可能很大,並且子串可能很多,人工分析不可能,於是他想寫個程序來先算算到底有多少個子串滿足條件。如果子串內容相同,但是開始或者結束位置不一樣,則被認爲是不同的子串。
注:子串一定是連續的。例如"010"有6個子串,分別是 "0, “1”, “0”, “01”, “10”, “010”
輸入描述:
第一行是一個整數k,表示子串中有k個1就有可能是病毒。其中 0 <= k <= 1 000 000
第二行是一個字符串,就是library的代碼部分的二進制表示。字符串長度 <= 1 000 000。並且字符串中只包含"0"或"1".
輸出描述:
輸出一個整數,所有滿足只包含k個1的子串的個數。
輸入例子1:
1
1010
輸出例子1:
6
例子說明1:
滿足條件的子串有:"1", "1", "10", "01", "10", "010".
二、Solution
這題和 能被 K 整除的子數組 很像…
方法一:dp
定義狀態: 表示字符 1 的個數爲 時,字符 0 的個數,以下面的數據爲例
k = 1
0010111
cnt 表示到達當前位置 時遇到的字符 1 的個數。
- 當 時,此時 cnt = 1,ans 應加上 (位置 2 的前面的 0 的個數爲 2)
- 當 時,此時 cnt = 2,ans 應加上 (位置 4 前面的 0 的個數爲 1 個)
- …
- 當 時,此時 cnt = 4,ans 應加上 (位置 6 前面的 0 的個數爲 0 個)
總結:當前位置的狀態依賴的是到達當前位置 時剩餘字符 1 的數量爲 cnt-k 時字符 0 的數量。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static class Solution {
void init() {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
int k = sc.nextInt();
char[] s = sc.next().toCharArray();
int n = s.length, cnt = 0, f[] = new int[n];
long ans = 0;
f[0] = 1;
for (int i = 0; i < n; i++) {
if (s[i] == '1')
cnt++;
if (cnt - k >= 0)
ans += f[cnt-k];
f[cnt]++;
}
System.out.println(ans);
}
}
public static void main(String[] args) throws IOException {
Solution s = new Solution();
s.init();
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,