等差子数组[O(n)判断数组是否为等差数列]

前言

如何判定一个数组是否为等差数列,可以直接排序O(nlogn),再不断求相邻数之间的差值,通过前后差值一致+传递性,完成等差数列的判定。但这没有充分利用等差数列的特性,强行将数排序,不如把每个数在等差数列的位置记下来,实现空间换时间。

一、等差子数组

在这里插入图片描述

二、空间换时间

排序,将凌乱的数按递增排序回来,时间复杂度不会小于O(nlogn),而通过公差 + 首项,充分利用等差数列的特性,得到每个数在等差数列中的位置,只要位置不重复,那么这个数组一定能排序成等差数列。

  1. 先取a = min,b = max,公差d = (b - a) / (nums.length - 1),不能完全除尽,说明不能排序成等差数列。
  2. 遍历nums,记录index = (x - a) / d,同样不能除尽,说明不能排除等差数列。
  3. 记录这些index是否出现过,重复出现说明不能排序成等差数列。
  4. 如果没有重复index,说明nums能排序成等差数列。
func checkArithmeticSubarrays(nums []int, l []int, r []int) []bool {
    // 主方法,遍历查询数组,得到答案并返回。
    ans := make([]bool,len(l))
    for i := 0 ;i < len(l);i++ {
        left,right := l[i],r[i]
        // 取最大和最小值
        b,a := getM(nums,left,right,1),getM(nums,left,right,-1)
        // 计算公差
        g1,g2 := b - a,right - left
        d := g1 / g2
        ans[i] = g1 % g2 == 0 && (d == 0 || isVaild(nums,left,right,a,d))
    }
    return ans
}
func isVaild(nums []int,left,right,a,d int) bool {
    set := map[int]interface{}{}
    for i := left;i <= right;i++ {
        t := (nums[i] - a) / d
        if _,ok := set[t];ok || (nums[i] - a) % d != 0 {
            return false
        }
        set[t] = struct{}{}
    }
    return true
}
func getM(nums []int,left,right,r int) int {
    m := nums[left]
    for i := left;i <= right;i++ {
        // 一正 一负 取min
        if m * r < nums[i] * r {
            m = nums[i]
        }
    }
    return m
}
// 等差数列:s[i + 1] - s[i] = s[1] - s[0]
// 根据左右下标,查找该区间内重排序后是否为等差数列。
// 这里是寻找子数组,而不是子序列。

总结

1)充分利用bg中的特点,挖掘潜在规律,将问题转换,让时间复杂度降到最低。利用等差数列中的公差+首项+index,完成O(n)排定数组是否能排序成等差数列。

参考资料

[1] LeetCode 等差子数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值