力扣9.30

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

给你一个整数数组 nums 。一个子数组 [numsl, numsl+1, ..., numsr-1, numsr] 的 和的绝对值 为 abs(numsl + numsl+1 + ... + numsr-1 + numsr)

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

abs(x) 定义如下:

  • 如果 x 是负整数,那么 abs(x) = -x
  • 如果 x 是非负整数,那么 abs(x) = x

数据范围

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

分析

最大子数组和的变式,可以求处最大子数组和和最小子数组和,然后取绝对值的max

代码

typedef long long LL;
class Solution {
public:
    const static int N = 1e5 + 5, INF = 0x3f3f3f3f;
    int dp1[N], dp2[N];
    int maxAbsoluteSum(vector<int>& nums) {
        int n = nums.size();
        int res = 0;
        dp1[0] = -INF;
        dp2[0] = INF; 
        for(int i = 1; i <= n; i ++ ) {
            dp1[i] = max(nums[i - 1], dp1[i - 1] + nums[i - 1]);
            dp2[i] = min(nums[i - 1], dp2[i - 1] + nums[i - 1]);
            res = max(res, abs(dp1[i]));
            res = max(res, abs(dp2[i]));
        }
        return res;
    }
};

1191. K 次串联后最大子数组之和

给定一个整数数组 arr 和一个整数 k ,通过重复 k 次来修改数组。

例如,如果 arr = [1, 2] , k = 3 ,那么修改后的数组将是 [1, 2, 1, 2, 1, 2]

返回修改后的数组中的最大的子数组之和。注意,子数组长度可以是 0,在这种情况下它的总和也是 0

由于 结果可能会很大,需要返回的 109 + 7 的 模 。

数据范围

  • 1 <= arr.length <= 105
  • 1 <= k <= 105
  • -104 <= arr[i] <= 104

分析

分类讨论,两种情况,对于k=1的情况,直接在长度为n的数组上做一次子数组最大和,对于k>1的情况,可能会出现起点和终点不在同一个区间内,因此需要对数组进行复制,而对于中间是否需要加上一整段区间,只需要看数组的和是否为正数,若是正数,则一定可以将整段区间插入到起点和终点之间。

代码

typedef long long LL;
class Solution {
public:
    const static LL N = 1e5 + 5, INF = 0x3f3f3f3f, mod = (LL)1e9 + 7;
    LL res = 0;
    LL dp[2 * N];
    LL kConcatenationMaxSum(vector<int>& arr, int k) {
        int n = arr.size();
        LL sum = 0;
        for(int i = 0; i < n; i ++ ) {
            sum += arr[i];
            sum %= mod;
        }
        dp[0] = 0;
        for(int i = 1; i <= n * (k > 1 ? 2 : 1); i ++ ) {
            dp[i] = max((LL)0, dp[i - 1] + (LL)arr[(i - 1) % n]);
            if(sum > 0 && k >= 2) res = max(res, dp[i] + sum * (k - 2) % mod);
            else res = max(res, dp[i]);
            dp[i] %= mod;
            res %= mod;
        }
        return res % mod;
    }
};

918. 环形子数组的最大和

给定一个长度为 n 的环形整数数组 nums ,返回 nums 的非空 子数组 的最大可能和 。

环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i] 的下一个元素是 nums[(i + 1) % n]nums[i] 的前一个元素是 nums[(i - 1 + n) % n]

子数组 最多只能包含固定缓冲区 nums中的每个元素一次。形式上,对于子数组 nums[i], nums[i + 1], ..., nums[j] ,不存在 i <= k1, k2 <= j 其中 k1 % n == k2 % n

数据范围

  • n == nums.length
  • 1 <= n <= 3 * 104
  • -3 * 104 <= nums[i] <= 3 * 104​

分析

​​​​​​令dp[i]表示以i结尾的最大子数组和,同时用len[i]记录长度,对于环形,我们可以开两倍数组将首位相接,然后跑一边最大子数组和并记录长度,若长度大于n,则说明需要删去首部一些点,由于我们已经记录了子数组的长度,所以可以轻松找到这段子数组的开头,之后找到前缀和小于0的最小值mins,将dp[i]减去mins,同时更新len即可

代码

class Solution {
public:
    const static int N = 3e4 + 5, INF = 0x3f3f3f3f;
    int dp[2 * N];
    int len[2 * N];
    int maxSubarraySumCircular(vector<int>& nums) {
        int n = nums.size();
        int res = -INF;
        dp[0] = -INF;
        for(int i = 1; i <= 2 * n; i ++ ) {
            if(dp[i - 1] + nums[(i - 1) % n] > nums[(i - 1) % n]) {
                dp[i] = dp[i - 1] + nums[(i - 1) % n];
                len[i] = len[i - 1] + 1;
            } else {
                dp[i] = nums[(i - 1) % n];
                len[i] = 1;
            }
            if(len[i] > n) {
                int t = len[i];
                int last = i - t + 1;
                while(i - last + 1 > n) {
                    dp[i] -= nums[(last - 1) % n];
                    last ++ ;
                }
                int minsum = 0, sum = 0;
                int pos = last - 1;
                for(int k = last; k <= i; k ++ ) {
                    sum += nums[(k - 1) % n];
                    if(minsum > sum) {
                        minsum = sum;
                        pos = k;
                    }
                }
                len[i] = i - pos;
                dp[i] -= minsum;
            }
            res = max(res, dp[i]);
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值