Leetcode 1749. 任意子数组和的最大绝对值

目录

1749. 任意子数组和的绝对值的最大值

思路解析

算法1--动态规划

算法2--前缀和


1749. 任意子数组和的绝对值的最大值

思路解析

算法1--动态规划

拿到这道题目,我们最朴素的想法就是枚举所有区间。但是这样的代价是O(n^{2}) ,面对 题目的数据量这样的代价是高昂的。所以,我们需要另寻他法。

首先这是一道 区间最优化题目。但从关键字 “区间” 而言,我们有 前缀和数组、树状数组、 线段树以及区间动规。

如果使用树状数组,那么在多次访问区间是较为低效的

如果使用线段树(分治思想),那么我们为了保证连续区间的特点需要对跨区情况需要花费O(n)的时间去维护最大绝对值。最后我们只需要访问整个区间即可,也就是最后复杂度会来到O(nlogn)。当然,如果你是采用记忆化搜索的,时间复杂度可以来到O(n)。

关键在于最大绝对值的维护,我们的第一个想法就是某一段区间内的和最大或者最小。那么题目就转换成最大子序列和 与 最小子序列和。借此,你能知道为什么线段树可以采用记忆化了。如果你敢兴趣,您可以移步到我的另一篇blog:经典题:最大子序列和_诶咦的博客-CSDN博客

AC代码

class Solution {
    struct Status {
        int min, max;
    };
public:
    int maxAbsoluteSum(vector<int>& nums) {
        int n_nums = nums.size();
        vector<Status> dp(n_nums);
        dp[0].min = nums[0], dp[0].max = nums[0];

        for (int i = 1; i < n_nums; ++i) {
            dp[i].min = min(dp[i - 1].min + nums[i], nums[i]);
            dp[i].max = max(dp[i - 1].max + nums[i], nums[i]);
        }

        int ans = abs(nums[0]);
        for (int i = 1; i < n_nums; ++i) {
            ans = max(ans, max(abs(dp[i].min), abs(dp[i].max)));
        }

        return ans;
    }
};

当然你也可以使用 “线段树(分治思想)” 作为一种基底编写代码。

算法2--前缀和

还记得我们面对 “区间” 关键字提出的做法吗?本质上来讲,树状数据也是一种前缀和数组且是线段树的优化。但很可惜,在多次访问这方面它不如原始的前缀和数组简单快捷。而区间和,例如区间 [l, r] 之间的元素和可以表示为 pre_sum[r] - pre_sum[l - 1]

表达式就变成了 abs(pre_sum[r] - pre_sum[l - 1]) 的最大值,那么我们知道只要 pre_sum[r] - pre_sum[l - 1] 的差值最大即可,也就是我们只要去寻找 pre_sum 的最大最小值即可。

AC代码:

class Solution {
public:
    int maxAbsoluteSum(vector<int>& nums) {
        int n_nums = nums.size();
        
        vector<int> pre_sum(n_nums + 1);
        pre_sum[0] = 0;
        for (int i = 1; i <= n_nums; ++i) {
            pre_sum[i] = pre_sum[i - 1] + nums[i - 1];
        }

        int max = 0, min = 0;
        for (int i = 1; i <= n_nums; ++i) {
            if (max < pre_sum[i]) max = pre_sum[i];
            if (min > pre_sum[i]) min = pre_sum[i];
        }

        return abs(max - min);
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值