【LeetCode 算法】Maximum Sum Circular Subarray 环形子数组的最大和 - 优先队列

文章介绍了如何解决环形整数数组的最大子数组和问题,方法是将环形数组扩展为线性数组,然后使用前缀和和优先队列来找到最大子数组和。在枚举过程中,通过维护前缀和的最小值来优化计算,整体时间复杂度为O(N^2(logN)^2),空间复杂度为O(N)。
摘要由CSDN通过智能技术生成

Maximum Sum Circular Subarray 环形子数组的最大和

问题描述:

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

环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i] 的下一个元素是 n u m s [ ( i + 1 ) m o d    n ] , n u m s [ i ] 的前一个元素是 n u m s [ ( i − 1 + n ) m o d    n ] nums[(i + 1) \mod n] , nums[i] 的前一个元素是 nums[(i - 1 + n) \mod n] nums[(i+1)modn]nums[i]的前一个元素是nums[(i1+n)modn]

子数组 最多只能包含固定缓冲区 nums 中的每个元素一次。形式上,对于子数组 n u m s [ i ] , n u m s [ i + 1 ] , . . . , n u m s [ j ] ,不存在 i < = k 1 , k 2 < = j 其中 k 1 m o d    n = = k 2 m o d    n nums[i], nums[i + 1], ..., nums[j] ,不存在 i <= k1, k2 <= j 其中 k1 \mod n == k2 \mod n nums[i],nums[i+1],...,nums[j],不存在i<=k1,k2<=j其中k1modn==k2modn

n = = n u m s . l e n g t h 1 < = n < = 3 ∗ 1 0 4 − 3 ∗ 1 0 4 < = n u m s [ i ] < = 3 ∗ 1 0 4 n == nums.length\\ 1 <= n <= 3 * 10^4\\ -3 * 10^4 <= nums[i] <= 3 * 10^4 n==nums.length1<=n<=31043104<=nums[i]<=3104

分析

昨天发的解决思路,算是比较难想的,对于思维与编码能力都有一定的要求。

今天可以换个思路,该思路是建立在 已经知道如何计算长度为N的数组中的最大子数组和的前提下。

requirements

知道如何计算长度为N的数组中的最大子数组和

首先必须知道前缀和,其次需要知道优先队列,最后还需要知道滑动窗口的思路。

如果上面的要求都没有达到,建议先搞明白,否则可能看不明白。

对于一个环形数组,要计算其最大的子数组和,而且这个子数组不能超过数组的长度N,所以可以使用2个数组前后拼接,这样就可以模拟一个环形数组。

此时得到的数组长度 2 N 2N 2N,即 0 → 2 N − 1 0\rightarrow 2N-1 02N1.

所以可以枚举可能的子数组的右端点right,而为了计算子数组的和,肯定要使用前缀和,所以在枚举的过程中计算出每个下标对应的presum,将其入优先队列。

而在枚举右端点到 下标 i i i时 ,此时需要得到 [ L , i ] [L,i] [L,i]的范围内的最大子数组和,就是使用 p r e s u m [ i ] − p r e s u m [ x ] presum[i]-presum[x] presum[i]presum[x],为了得到最大子数组和S,就必须选择合法范围内的最小presum,所以使用优先队列进行过滤。

优先队列的时间复杂度 O ( N l o g N ) O(NlogN) O(NlogN),枚举长度为 2 N 2N 2N,所以整体的时间复杂度为 O ( N 2 ( l o g N ) 2 ) O({N^{2}}(logN)^{2}) O(N2(logN)2)

代码

优先队列

class Solution {
    public int maxSubarraySumCircular(int[] nums) {
        int ans = Integer.MIN_VALUE,n = nums.length;
        //val -idx
        PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a,b)->{
            if(a[0]==b[0]) return a[1]-b[1];
            return a[0]-b[0];
        });
        int sum = 0;
        pq.offer(new int[]{0,-1});
        // i-j+1>n       j<i+1-n
        for(int i =0;i<2*n-1;i++){
            while(!pq.isEmpty()&& pq.peek()[1]<i+1-n){
                pq.poll();
            }
            int cur = nums[i%n];
            ans = Math.max(ans,cur);
            sum += cur;
            if(!pq.isEmpty()){
                ans = Math.max(ans,sum - pq.peek()[0]); 
            }
            pq.offer(new int[]{sum,i+1});
        }
        return ans;
    }
}

时间复杂度 O ( N 2 ( l o g N ) 2 ) O({N^{2}}(logN)^{2}) O(N2(logN)2)

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

Tag

Array

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Eric.Cui

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

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

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

打赏作者

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

抵扣说明:

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

余额充值