列表

详情


100348. 统计 1 显著的字符串的数量

给你一个二进制字符串 s

请你统计并返回其中 1 显著 子字符串 的数量。

如果字符串中 1 的数量 大于或等于 0 的数量的 平方,则认为该字符串是一个 1 显著 的字符串 。

 

示例 1:

输入:s = "00011"

输出:5

解释:

1 显著的子字符串如下表所示。

i j s[i..j] 0 的数量 1 的数量
3 3 1 0 1
4 4 1 0 1
2 3 01 1 1
3 4 11 0 2
2 4 011 1 2

示例 2:

输入:s = "101101"

输出:16

解释:

1 不显著的子字符串如下表所示。

总共有 21 个子字符串,其中 5 个是 1 不显著字符串,因此有 16 个 1 显著子字符串。

i j s[i..j] 0 的数量 1 的数量
1 1 0 1 0
4 4 0 1 0
1 4 0110 2 2
0 4 10110 2 3
1 5 01101 2 3

 

提示:

相似题目

计数二进制子串

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int numberOfSubstrings(string s) { } };

golang 解法, 执行用时: 53 ms, 内存消耗: 6.5 MB, 提交时间: 2024-07-29 17:48:54

// 枚举右端点,在枚举的同时,维护 0 的下标列表 a。
func numberOfSubstrings(s string) (ans int) {
	tot1 := 0
	a := []int{-1} // 哨兵
	for right, b := range s {
		if b == '0' {
			a = append(a, right)
		} else {
			ans += right - a[len(a)-1]
			tot1++
		}
		for k := len(a) - 1; k > 0 && (len(a)-k)*(len(a)-k) <= tot1; k-- {
			cnt0 := len(a) - k
			cnt1 := right - a[k] + 1 - cnt0
			ans += max(a[k]-a[k-1]-max(cnt0*cnt0-cnt1, 0), 0)
		}
	}
	return
}

// 枚举左端点
func numberOfSubstrings2(s string) (ans int) {
	a := []int{}
	for i, b := range s {
		if b == '0' {
			a = append(a, i)
		}
	}

	n := len(s)
	tot1 := n - len(a)
	a = append(a, n) // 哨兵

	for left, b := range s {
		if b == '1' {
			ans += a[0] - left // 不含 0 的子串个数
		}
		for k, j := range a[:len(a)-1] {
			cnt0 := k + 1
			if cnt0*cnt0 > tot1 {
				break
			}
			cnt1 := j - left - k
			ans += max(a[k+1]-j-max(cnt0*cnt0-cnt1, 0), 0)
		}
		if b == '0' {
			a = a[1:] // 这个 0 后面不会再枚举到了
		}
	}
	return
}

java 解法, 执行用时: 92 ms, 内存消耗: 44.3 MB, 提交时间: 2024-07-29 17:47:23

class Solution {
    public int numberOfSubstrings(String S) {
        char[] s = S.toCharArray();
        int n = s.length;
        int m = 0;
        int[] a = new int[n + 1];
        for (int i = 0; i < n; i++) {
            if (s[i] == '0') {
                a[m++] = i;
            }
        }

        int tot1 = n - m;
        a[m] = n; // 哨兵

        int ans = 0;
        int i = 0; // >= left 的第一个 0 的下标是 a[i]
        for (int left = 0; left < n; left++) {
            if (s[left] == '1') {
                ans += a[i] - left; // 不含 0 的子串个数
            }
            for (int k = i; k < m; k++) {
                int cnt0 = k - i + 1;
                if (cnt0 * cnt0 > tot1) {
                    break;
                }
                int cnt1 = a[k] - left - (k - i);
                ans += Math.max(a[k + 1] - a[k] - Math.max(cnt0 * cnt0 - cnt1, 0), 0);
            }
            if (s[left] == '0') {
                i++; // 这个 0 后面不会再枚举到了
            }
        }
        return ans;
    }
    
    // 枚举右端点
    public int numberOfSubstrings2(String S) {
        char[] s = S.toCharArray();
        int ans = 0;
        int tot1 = 0;
        int[] a = new int[s.length + 1];
        a[0] = -1; // 哨兵
        int m = 1;
        for (int right = 0; right < s.length; right++) {
            if (s[right] == '0') {
                a[m++] = right;
            } else {
                ans += right - a[m - 1];
                tot1++;
            }
            for (int k = m - 1; k > 0 && (m - k) * (m - k) <= tot1; k--) {
                int cnt0 = m - k;
                int cnt1 = right - a[k] + 1 - cnt0;
                ans += Math.max(a[k] - a[k - 1] - Math.max(cnt0 * cnt0 - cnt1, 0), 0);
            }
        }
        return ans;
    }
}

cpp 解法, 执行用时: 163 ms, 内存消耗: 15.5 MB, 提交时间: 2024-07-29 17:46:31

class Solution {
public:
    int numberOfSubstrings(string s) {
        int ans = 0, tot1 = 0;
        vector<int> a = {-1}; // 哨兵
        for (int right = 0; right < s.length(); right++) {
            char b = s[right];
            if (b == '0') {
                a.push_back(right);
            } else {
                ans += right - a.back();
                tot1++;
            }
            for (int k = a.size() - 1; k && (a.size() - k) * (a.size() - k) <= tot1; k--) {
                int cnt0 = a.size() - k;
                int cnt1 = right - a[k] + 1 - cnt0;
                ans += max(a[k] - a[k - 1] - max(cnt0 * cnt0 - cnt1, 0), 0);
            }
        }
        return ans;
    }

    // 枚举左端点
    int numberOfSubstrings2(string s) {
        int n = s.length();
        vector<int> a;
        for (int i = 0; i < n; i++) {
            if (s[i] == '0') {
                a.push_back(i);
            }
        }

        int tot1 = n - a.size();
        a.push_back(n); // 哨兵

        int ans = 0, i = 0; // >= left 的第一个 0 的下标是 a[i]
        for (int left = 0; left < n; left++) {
            if (s[left] == '1') {
                ans += a[i] - left; // 不含 0 的子串个数
            }
            for (int k = i; k < a.size() - 1; k++) {
                int cnt0 = k - i + 1;
                if (cnt0 * cnt0 > tot1) {
                    break;
                }
                int cnt1 = a[k] - left - (k - i);
                ans += max(a[k + 1] - a[k] - max(cnt0 * cnt0 - cnt1, 0), 0);
            }
            if (s[left] == '0') {
                i++; // 这个 0 后面不会再枚举到了
            }
        }
        return ans;
    }
};

python3 解法, 执行用时: 4471 ms, 内存消耗: 18.2 MB, 提交时间: 2024-07-29 17:45:38

# 枚举子串中的 0 的个数
class Solution:
    # 枚举左端点
    def numberOfSubstrings1(self, s: str) -> int:
        n = len(s)
        a = [i for i, b in enumerate(s) if b == '0']
        tot1 = n - len(a)
        a.append(n)  # 哨兵
        ans = i = 0  # >= left 的第一个 0 的下标是 a[i]
        for left, b in enumerate(s):
            if b == '1':
                ans += a[i] - left  # 不含 0 的子串个数
            for k in range(i, len(a) - 1):
                cnt0 = k - i + 1
                if cnt0 * cnt0 > tot1:
                    break
                cnt1 = a[k] - left - (k - i)
                # 可以改成手动比大小,那样更快
                ans += max(a[k + 1] - a[k] - max(cnt0 * cnt0 - cnt1, 0), 0)
            if b == '0':
                i += 1  # 这个 0 后面不会再枚举到了
        return ans
        
    # 枚举右端点
    def numberOfSubstrings2(self, s: str) -> int:
        ans = tot1 = 0
        a = [-1]  # 哨兵
        for right, b in enumerate(s):
            if b == '0':
                a.append(right)
            else:
                ans += right - a[-1]  # 不含 0 子串的个数
                tot1 += 1
            for k in range(len(a) - 1, 0, -1):
                cnt0 = len(a) - k
                if cnt0 * cnt0 > tot1:
                    break
                cnt1 = right - a[k] + 1 - cnt0
                # 可以改成手动比大小,那样更快
                ans += max(a[k] - a[k - 1] - max(cnt0 * cnt0 - cnt1, 0), 0)
        return ans
        
    # 更快写法
    def numberOfSubstrings(self, s: str) -> int:
        ans = tot1 = 0
        a = [-1]  # 哨兵
        for right, b in enumerate(s):
            if b == '0':
                a.append(right)
            else:
                ans += right - a[-1]  # 不含 0 子串的个数
                tot1 += 1
            for k in range(len(a) - 1, 0, -1):
                cnt0 = len(a) - k
                if cnt0 * cnt0 > tot1:
                    break
                cnt1 = right - a[k] + 1 - cnt0
                d = cnt0 * cnt0 - cnt1
                if d <= 0:
                    ans += a[k] - a[k - 1]
                elif (res := a[k] - a[k - 1] - d) > 0:
                    ans += res
        return ans

上一题