📜  计数仅由一位整数组成的子数组(1)

📅  最后修改于: 2023-12-03 14:57:25.953000             🧑  作者: Mango

计数仅由一位整数组成的子数组

子数组是指在一个数组中连续的一段元素构成的数组。给定一个仅由数字组成的数组,计算其中仅包含一种数字的子数组的个数。

例如,对于数组 [1,2,3,4,5],仅包含一种数字的子数组有 [1]、[2]、[3]、[4]、[5]、[1,2,3,4,5],因此该数组中共有 6 个仅包含一种数字的子数组。注:空数组也被视为一个子数组,因此其也算作一个仅包含一种数字的子数组。

解法一:暴力枚举

最简单的做法是直接枚举数组中的每一个子数组,判断它是否是一个仅包含一种数字的子数组。

时间复杂度:O(n^2)

代码如下:

class Solution:
    def countSubOneNum(self, nums: List[int]) -> int:
        n = len(nums)
        res = 0
        for i in range(n):
            for j in range(i, n):
                if len(set(nums[i:j+1])) == 1:
                    res += 1
        return res
解法二:滑动窗口

对于每个i,我们求出该位置开始的最长连续相同数字的长度,设为len。那么以i为起点的符合条件的子序列数量就是len+(len-1)+(len-2)+...+1 = len*(len+1)/2。我们只需要遍历一遍数组即可得到所有符合条件的子序列数量。

时间复杂度:O(n)

代码如下:

class Solution:
    def countSubOneNum(self, nums: List[int]) -> int:
        n = len(nums)
        res, i = 0, 0
        while i < n:
            j = i + 1
            while j < n and nums[j] == nums[i]:
                j += 1
            len = j - i
            res += len * (len+1) // 2
            i = j
        return res
解法三:双指针

我们用两个指针i和j,分别指向当前的连续子序列的首尾元素。我们不断移动j,直到发现下一个元素不等于当前连续子序列的首元素,此时j所在的位置就是一个新的连续子序列的起始位置。我们因此可以计算当前连续子序列的所有符合条件的子序列数量,然后再将i移动到j的位置,继续寻找下一个连续子序列。

时间复杂度:O(n)

代码如下:

class Solution:
    def countSubOneNum(self, nums: List[int]) -> int:
        n = len(nums)
        res, i = 0, 0
        while i < n:
            j = i + 1
            while j < n and nums[j] == nums[i]:
                j += 1
            len = j - i
            res += len*(len+1)//2
            i = j
        return res

以上三种解法的时间复杂度分别为O(n^2)、O(n)和O(n)。对于较大的数组,明显第一种解法太慢了,而第二种和第三种解法则速度较快。 我们平时要养成尽量不要用暴力枚举的好习惯,因为暴力枚举的时间复杂度通常都很高,而且在面试中也并不被看好。