题意
给你一个二进制数组nums 。如果一个子数组中 不存在 两个 相邻 元素的值 相同 的情况,我们称这样的子数组为 交替子数组 。
返回数组 nums 中交替子数组的数量。
示例 1:
输入: nums = [0,1,1,1]
输出: 5
解释:
以下子数组是交替子数组:[0] 、[1] 、[1] 、[1] 以及 [0,1] 。
示例 2:
输入: nums = [1,0,1,0]
输出: 10
解释:
数组的每个子数组都是交替子数组。可以统计在内的子数组共有 10 个。
提示:
1
<
=
n
u
m
s
.
l
e
n
g
t
h
<
=
1
0
5
1 <= nums.length <= 10^5
1<=nums.length<=105
nums[i] 不是 0 就是 1 。
思路1 朴素枚举
第一想法肯定是枚举子数组的起点和终点,如果符合条件的话,答案就加1
稍微优化了下,首先枚举子数组的起点,然后从起点往后遍历,如果这一位和上一位不相等的话,答案加1;否则,该起点的枚举就结束了,break掉。
因为长度为1的子数组肯定是符合要求的,所以就预先把这些加到答案里,后面的遍历只是为了找出长度>=2的子数组
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)
空间复杂度:
O
(
1
)
O(1)
O(1)
func countAlternatingSubarrays(nums []int) int64 {
var ans int64 = int64(len(nums))
for i := 0; i < len(nums); i ++ {//起点
for j := i + 1; j < len(nums); j ++ {
if nums[j] != nums[j-1] {
ans++
}else{
break
}
}
}
return ans
}
思路2 递推思想
考虑如何优化思路1,其实可以用一个递推的思想,
假设当前枚举到下标为i的元素,前面已经有now个符合条件的子数组,那么如果下标为i的元素和下标为i-1的元素不同,相当于以下标为i的元素结尾的符合条件的子数组一共有now+1个,其中+1是第i个单独元素的集合,这个时候now也要加1,因为这个元素对后面的元素也是有贡献的;
如果下标为i的元素和下标为i-1的元素相同,相当于以下标为i的元素结尾的符合条件的子数组只有1个,即第i个单独元素的集合,这个时候now也要重新计数。
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
n
)
O(n)
O(n)
func countAlternatingSubarrays(nums []int) int64 {
dp := make([]int64,len(nums))
dp[0] = 1
var now int64 = 1
for i := 1; i < len(nums); i ++ {
dp[i] = dp[i-1] + 1 //加上第i个单独元素的集合
if nums[i] == nums[i-1] {
now = 1 //重新计数
}else{
dp[i] += now
now = now + 1
}
}
return dp[len(nums)-1]
}
思路3 优化空间
思路2的dp数组转移的时候只用到了dp[i-1]的状态,其实完全可以用变量来替代
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)
func countAlternatingSubarrays(nums []int) int64 {
var ans,now int64 = 0,0
var las int = -1
for _,elem := range nums {
if las == elem {//相等的话
now = 1 //只有elem这个子数组符合要求
}else{
now = now + 1 //在加上elem这个子数组
}
las = elem
ans = ans + now
}
return ans
}