算法日常・每日刷题--<动态规划>20

918. 环形子数组的最大和 - 力扣(LeetCode)

题目描述

给定一个长度为 n 的环形整数数组 nums,环形数组意味着数组的末端将会与开头相连呈环状。找出这个环形数组的非空连续子数组的最大和。

子数组:必须是连续的,环形代表子数组可以跨数组首尾,例如数组 [5,-3,5],可以选取 [5,5](第一个 5 和最后一个 5)。

核心思路

环形子数组最大和只有两种情况:

  1. 不跨首尾 :普通最大子数组和(就是 LeetCode53 最大子序和),记为ret1
  2. 跨首尾 :子数组包含数组头部 + 尾部,等价于总和减去中间一段最小子数组和 ,sum - ret2,ret2是最小子数组和

⚠️ 边界特例:数组全部都是负数 此时总和减去最小子数组,会得到空数组(不合法,题目要求子数组非空),这种情况直接返回普通最大子数组(也就是数组里最大的单个负数)。

状态定义

  • fx[i]:以i下标结尾的最大子数组和
  • gx[i]:以i下标结尾的最小子数组和

状态转移:

遍历过程中:

  • ret1:记录全局最大子数组和
  • ret2:记录全局最小子数组和
  • sum:整个数组总和
  • flag:标记数组是否存在正数,用来判断是否全负
cpp 复制代码
class Solution {
public:
    int maxSubarraySumCircular(vector<int>& nums) {
        int n=nums.size();
        vector<int>fx(n,0);
        auto gx=fx;
        fx[0]=nums[0];
        gx[0]=nums[0];
        int ret1=nums[0];
        int ret2=nums[0];
        int sum=nums[0];
        int flag=0;
        for(int i=1;i<n;i++)
        {
            fx[i]=max(fx[i-1]+nums[i],nums[i]);
            gx[i]=min(gx[i-1]+nums[i],nums[i]);
            ret1=ret1>fx[i]?ret1:fx[i];
            ret2=ret2<gx[i]?ret2:gx[i];
            sum+=nums[i];
            if(nums[i]>0)
            flag=1;
        }
        if(flag==0)
        return ret1;
        return max(ret1,sum-ret2);
    }
};
相关推荐
青少儿编程课堂2 小时前
迪杰斯特拉(Dijkstra)算法:单源最短路与赛场路线规划
c++·python·算法·bfs·信息学竞赛
不会就选b2 小时前
算法日常・每日刷题--<动态规划>19
算法·leetcode·职场和发展
没有钱的钱仔4 小时前
协方差矩阵含义
算法·机器学习·矩阵
垆边人似月.4 小时前
华为机试题 :和为 K 的子数组个数
算法·leetcode·华为
三*一4 小时前
优化修整算法
前端·javascript·算法
达子6664 小时前
RUST 图解 第 3 章:通用编程概念(Common Programming Concepts)
开发语言·算法·rust
夏幻灵5 小时前
每日一题:LeetCode 165:比较版本号
算法·leetcode·职场和发展
道尔柯南5 小时前
C++ 面向对象编程入门:类和对象(上)
开发语言·c++·算法