202111-15更文-leetcode918:环形子数组的最大和

154 阅读1分钟

这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

leetcode918:环形子数组的最大和

前文

本文仅为leetcode刷题过程中的想法记录,并非最佳解决方案。

题目信息

给定一个由整数数组 A 表示的环形数组 C,求 C 的非空子数组的最大可能和。

在此处,环形数组意味着数组的末端将会与开头相连呈环状。(形式上,当0 <= i < A.length 时 C[i] = A[i],且当 i >= 0 时 C[i+A.length] = C[i])

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

解题思路分析

与求子数组的最大和类似,在解决该题目时,正常顺序下需要对于常规的最大子数和进行求解。也就是利用一个res变量,当res小于0时,res值更新为遍历的数组值;反之,res为之前的res值与当前节点相加之和。由于该数组是环形数组,那么需要考虑一个特殊情况,最大子数组位于数组两边。那么我们可以换一种理解,即求最小子数组和,最大子数组和也就等于总和减最小子数组。与此同时,还有一种特殊情况,也就是所有的数组元素均小于0,那么最大子数组的和也就等于遍历过程中所得到的最大值。该题至此解题完毕,也就是动态规划的一种特殊处理,相当于同时对最大和以及最小和进行动态规划运算。代码如下:

public int maxSubarraySumCircular(int[] nums) {
    if(nums.length == 0){
        return 0;
    }
    int total = 0;
    int max = Integer.MIN_VALUE;
    int res_max = 0;
    int min = Integer.MAX_VALUE;
    int res_min = 0;
    for (int i = 0; i < nums.length ; i++) {
        total += nums[i];
        if(res_max < 0){
            res_max = nums[i];
        }else{
            res_max = res_max + nums[i];
        }
        if(res_min > 0){
            res_min = nums[i];
        }else{
            res_min = res_min + nums[i];
        }
        max = Math.max(res_max,max);
        min = Math.min(res_min,min);
    }
    if(total == min){
        return max;
    }else{
        return Math.max(max,total-min);
    }
}

复杂度分析

  • 时间复杂度 o(n)
  • 空间复杂度 o(1)

后记

  • 千古兴亡多少事?悠悠。不尽长江滚滚流。