返回

深入剖析 LeetCode 89:掌握计数二进制子串的奥秘

Android

引言

算法作为计算机科学领域不可或缺的一部分,为我们提供了解决复杂问题的有效方法。而 LeetCode 作为算法学习的宝贵平台,提供了一个绝佳的训练场,让我们磨练技能,提升对算法的理解。今天,我们将踏上 LeetCode 89 题的探索之旅,深入解析如何巧妙地计数二进制子串。

问题陈述

LeetCode 89 题的任务看似简单:给定一个只包含 0 和 1 的字符串,计算具有相同数量 0 和 1 的非空连续子字符串的数量。乍看之下,我们可以通过暴力搜索的方法,遍历字符串的每个子串,并逐一检查其是否满足条件。然而,这种朴素的解法时间复杂度为 O(n^2),对于较长的字符串来说,效率低下。

动态规划的魅力

为了有效地解决这个问题,我们需要借助动态规划的强大力量。动态规划是一种分治思想,将问题分解成更小的子问题,逐一解决,并将子问题的解存储起来,避免重复计算。在 LeetCode 89 题中,我们将利用动态规划的思想,以线性时间复杂度 O(n) 解决问题。

算法详解

我们引入一个数组 dp,其中 dp[i] 表示以第 i 个字符结尾的子串中,连续 0 和 1 个数相等的子串数量。对于每个字符,我们可以根据其值是 0 还是 1,来更新 dp 数组。具体而言,如果当前字符为 0,那么以其结尾的满足条件的子串数量为以其前一个字符结尾的相同子串数量加 1;如果当前字符为 1,那么以其结尾的满足条件的子串数量为以其前两个字符结尾的相同子串数量加 1。

代码实现

def countBinarySubstrings(s):
    dp = [0] * len(s)
    for i in range(1, len(s)):
        if s[i] == s[i - 1]:
            dp[i] = dp[i - 1] + 1
        else:
            dp[i] = 1 if i < 2 else dp[i - 1] + dp[i - 2]
    return sum(dp)

代码解析

在代码中,我们首先创建了一个与原字符串长度相同的数组 dp,用于存储每个子串的连续 0 和 1 个数相等的子串数量。然后,我们遍历字符串中的每个字符,根据其值更新 dp 数组。最后,我们将 dp 数组中所有元素相加,得到满足条件的子串总数。

示例应用

让我们举一个示例来理解算法的实际应用。给定字符串 s = "00110011",我们可以计算出 dp 数组如下:

i s[i] dp[i]
0 0 0
1 0 1
2 1 1
3 1 2
4 0 3
5 0 4
6 1 5
7 1 6

因此,字符串 "00110011" 中具有相同数量 0 和 1 的连续子串数量为 6。

结语

通过对 LeetCode 89 题的深入探索,我们不仅掌握了一种巧妙的算法技巧,还领略了动态规划的强大之处。动态规划让我们得以将复杂问题分解成更小的子问题,逐步解决,从而以更高的效率得到最优解。算法学习的旅程永无止境,愿我们不断探索,不断提升,在算法的海洋中乘风破浪。