【力扣 - 每日一题】3101. 交替子数组计数 | 朴素枚举 + 递推思想 + 优化空间 | Go

Problem: 3101. 交替子数组计数

题意

给你一个二进制数组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
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值