leetcode
leetcode 601 ~ 650
计数二进制子串

计数二进制子串

难度:

标签:

题目描述

代码结果

运行时间: 61 ms, 内存: 16.4 MB


/*
 * 思路:
 * 通过使用 Java Stream API 来计算具有相同数量的连续 0 和 1 的子字符串。
 * 我们使用一个列表来存储每个连续组的长度,然后计算这些组是否可以构成符合条件的子字符串。
 */
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
 
public class Solution {
    public int countBinarySubstrings(String s) {
        List<Integer> groups = new ArrayList<>();
        int count = 1;
        for (int i = 1; i < s.length(); i++) {
            if (s.charAt(i) == s.charAt(i - 1)) {
                count++;
            } else {
                groups.add(count);
                count = 1;
            }
        }
        groups.add(count);
        return IntStream.range(1, groups.size())
                        .map(i -> Math.min(groups.get(i - 1), groups.get(i)))
                        .sum();
    }
}

解释

方法:

该题解的思路是用两个变量cnt和n分别记录当前连续字符的个数和前一种连续字符的个数。遍历字符串,若当前字符与前一个字符相同,则cnt加1;否则,将前一种字符的个数n更新为cnt,cnt重置为1。每次更新n后,若cnt<=n,说明存在一个符合条件的子串,ret加1。最后返回ret即可。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在遇到不同字符时,你选择更新前一个字符的连续个数`n`为`cnt`,而不是继续累加到`cnt`?
在遇到不同字符时,我们需要切换统计对象,因为题目要求我们统计的是连续的0和1形成的子串,例如`01`或`10`。当字符从`0`变为`1`或从`1`变为`0`时,前一个字符的统计应该结束,开始新字符的统计。因此,我们需要记录前一个字符的连续个数`n`,以便与新字符的连续个数`cnt`进行比较,以判断是否形成了符合条件的子串。如果继续累加到`cnt`,则会混淆不同字符的界限,从而无法正确计算符合条件的二进制子串的数量。
🦆
在判断`cnt <= n`时,是否意味着只有当当前字符的连续长度小于或等于前一个字符的连续长度时,我们才认为找到了一个有效的子字符串?
是的,这个条件`cnt <= n`确实意味着只有当当前字符的连续长度小于或等于前一个字符的连续长度时,我们才认为找到了一个有效的子字符串。这是因为有效的子字符串需要由相等数量的`0`和`1`组成,例如`01`或`1100`。当当前字符的连续数小于或等于前一个字符的连续数时,我们可以确保从前一个字符的序列中取出足够数量的字符来与当前字符匹配,形成有效的子字符串。
🦆
算法中是否有处理字符串开头是`0`或`1`的不同情况,这会对计数有何影响?
算法初始化`c0`为`s[0]`,即字符串的第一个字符,这确保了无论字符串开始于`0`还是`1`,都能正确处理。初始化过程将自动适应第一个字符的类型,并开始计数。这种初始化方式不会对计数产生负面影响,而是确保从第一个字符开始即正确地统计连续的字符数。
🦆
在算法中,变量`c0`被初始化为`s[0]`,即字符串的第一个字符。如果字符串中所有字符都相同,输出结果会是什么?是否符合题目要求?
如果字符串中所有字符都相同,例如`1111`或`0000`,那么算法将不会找到任何有效的二进制子字符串,因为不存在必要的字符变化(从`0`到`1`或从`1`到`0`)。在这种情况下,输出结果将是`0`。这是符合题目要求的,因为题目要求的是计数那些由相等数量的连续`0`和`1`组成的子字符串,而在全是相同字符的情况下,这样的子字符串不存在。

相关问题

字符串的编码与解码

字符串的编码与解码