📅  最后修改于: 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)。对于较大的数组,明显第一种解法太慢了,而第二种和第三种解法则速度较快。 我们平时要养成尽量不要用暴力枚举的好习惯,因为暴力枚举的时间复杂度通常都很高,而且在面试中也并不被看好。