【前綴和】B004_NK_病毒檢測(暴力 / 累加)

一、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

定義狀態f[cntk]f[cnt-k] 表示字符 1 的個數爲 cntkcnt-k 時,字符 0 的個數,以下面的數據爲例

k = 1
0010111

cnt 表示到達當前位置 ii 時遇到的字符 1 的個數。

  • i=2i = 2 時,此時 cnt = 1,ans 應加上 f[cnt1]=2f[cnt-1] = 2(位置 2 的前面的 0 的個數爲 2)
  • i=4i = 4 時,此時 cnt = 2,ans 應加上 f[cnt1]=f[1]=1f[cnt-1] = f[1] = 1(位置 4 前面的 0 的個數爲 1 個)
  • i=6i = 6 時,此時 cnt = 4,ans 應加上 f[cnt1]=f[3]=0f[cnt-1] = f[3] = 0(位置 6 前面的 0 的個數爲 0 個)

總結:當前位置的狀態依賴的是到達當前位置 ii 時剩餘字符 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();
    }
}

複雜度分析

  • 時間複雜度:O()O()
  • 空間複雜度:O()O()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章