【LeetCode 算法】Maximum Absolute Sum of Any Subarray 任意子数组和的绝对值的最大值-前缀和

Maximum Absolute Sum of Any Subarray 任意子数组和的绝对值的最大值

问题描述:

给你一个整数数组 nums 。一个子数组 [ n u m s l , n u m s l + 1 , . . . , n u m s r − 1 , n u m s r ] [nums_l, nums_{l+1}, ..., nums_{r-1}, nums_{r}] [numsl,numsl+1,...,numsr1,numsr] 的 和的绝对值 为 a b s ( n u m s l + n u m s l + 1 + . . . + n u m s r − 1 + n u m s r ) abs(nums_l + nums_{l+1} + ... + nums_{r-1} + nums_{r}) abs(numsl+numsl+1+...+numsr1+numsr)

请你找出 n u m s nums nums 中 和的绝对值 最大的任意子数组(可能为空),并返回该 最大值 。

abs(x) 定义如下:

如果 x 是负整数,那么 a b s ( x ) = − x abs(x) = -x abs(x)=x
如果 x 是非负整数,那么 a b s ( x ) = x abs(x) = x abs(x)=x

1 < = n u m s . l e n g t h < = 1 0 5 − 1 0 4 < = n u m s [ i ] < = 1 0 4 1 <= nums.length <= 10^5\\ -10^4 <= nums[i] <= 10^4 1<=nums.length<=105104<=nums[i]<=104

分析

暴力

最简单的方法就是枚举出所有可能的子数组,计算其和的绝对值,然后取max。但是子数组的数量规模是 N 2 N^2 N2,所以暴力会TLE,而且即使计算出了子数组,计算其和也是需要时间的。

因为最终需要知道子数组绝对值最大值。

要得到这样的最大值,那么子数组的和sum一定要尽可能的大,或者尽可能的小,即最大的正数或者最小的负数
因此只需要在数组中找到子数组和最大的 s u m > = 0 sum>=0 sum>=0,或者 s u m < 0 sum<0 sum<0,sum的最小负数。

到这里,就和某个问题很像了

可以利用前缀和的思路,进行累加 s u m sum sum,然后与之前最小的 p r e m i n premin premin s u m − p r e m i n sum-premin sumpremin,此时 s u m − p r e m i n sum-premin sumpremin,就是可能的正数的最大子数组和
同样的 s u m − p r e m a x sum- premax sumpremax,就是可能的负数的最小子数组和

代码

前缀和

public int maxAbsoluteSum(int[] nums) {
        int n = nums.length, ans = nums[0];
        int premax = 0,premin = 0;
        int sum = 0 ;
        for(int i = 0;i<n;i++){ 
            sum += nums[i]; 
            int a = sum - premin; // 非负数的最大
            int b = premax -sum;//负数的绝对值最大
            ans = Math.max(ans,Math.max(b,a));
            premin = Math.min(sum,premin);
            premax = Math.max(sum,premax);
        }
        return ans;
    }

时间复杂度 O ( N ) O(N) O(N)

空间复杂度 O ( 1 ) O(1) O(1)

前缀和

public int maxAbsoluteSum(int[] nums) {
        int s = 0, mx = 0, mn = 0;
        for (int x : nums) {
            s += x;
            // mx = Math.max(mx, s);
            // mn = Math.min(mn, s);
            if (s > mx) mx = s;
            else if (s < mn) mn = s; // 效率更高的写法
        }
        return mx - mn; 
    }

时间复杂度 O ( N ) O(N) O(N)

空间复杂度 O ( 1 ) O(1) O(1)

灵神的代码更精简,不过他是从前缀和的另一个角度来看这个问题的,所以有点不一样。

Tag

Array

Presum

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Eric.Cui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值