首页 > 其他分享 >LeetCode 918. 环形子数组的最大和

LeetCode 918. 环形子数组的最大和

时间:2023-09-11 14:07:00浏览次数:41  
标签:最大 nums int 环形 我们 vector 918 数组 LeetCode

环形子数组的最大和(medium)

题目链接:

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

示例 1:

输入:nums = [1,-2,3,-2]
输出:3
解释:从子数组 [3] 得到最大和 3

示例 2:

输入:nums = [5,-3,5]
输出:10
解释:从子数组 [5,5] 得到最大和 5 + 5 = 10

示例 3:

输入:nums = [3,-2,2,-3]
输出:3
解释:从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3

题目解析

这道题比较麻烦,我们给定的数组实际上是一个不连续的,但是我们的在逻辑上要求他们连续.也就是最后一个元素之后,接着就是我们第一个元素.这里面要求我们的需要进行处理.这道题也是要求我们的求连续子数组的最大连续和.

算法原理

状态表示

按照经验,我们以...为结尾表示状态.

dp[i]:表示以i位置为结尾,我们最大子数组最大的连续和.

这道题优点问题,我们不知道数组什么时候结束.但是我们求连续子数组的最大和无非就是下面的两个情况.

image-20230910213241745

那么此时我我们发现两个关键点.

  • 对于情况1,我们求最大和就可以了
  • 对于情况2, 我们整个数组的和是确定,求最大和,那么我们求最小的和不就可以吗,然后一减

此时定义两个状态

  • f[i]: 表示以i位置,我们子数组的最大和
  • g[i]: 表示以i位置,我们子数组的最小和

状态转移方程

我们只谈g[i].这里我们想一下.对于我们的nums[i].这里我们可以有两个选择.

  • 选择nums[i]这一个元素作为我们的子数组 g[i]= nums[i]
  • 和i-1联合作为子数组. g[i] = dp[i-1]+nums[i]

那么这里我们求最小值g[i] = min(nums[i], g[i]+nums[i]);

初始化

仍旧只谈给g[i].这里添加一个辅助节点.那么对于满足g[1]=v[0],只需要g[0]=0就可以了.

填表顺序

从左向右填,两个一起填.

返回值

三个变量,一个记录最大和,一个记录总和,一个记录最小和.我们返回最大和以及总和减去最小和的较大值.

编写代码

class Solution {
public:
    int maxSubarraySumCircular(vector<int>& nums) {
        if(nums.empty())
        return 0;
        int n = nums.size();
        vector<int> f(n+1, 0);
        vector<int> g(n+1, 0);
        int sum = 0;
        int maxNum =  INT_MIN;
        int minNum =  INT_MAX;
        for(int i = 1; i <= n; i++)
        {
            sum += nums[i-1];
            f[i] = std::max(f[i-1]+nums[i-1], nums[i-1]);
            maxNum = std::max(maxNum, f[i]);
            g[i] = std::min(g[i-1]+nums[i-1], nums[i-1]);
            minNum = std::min(minNum, g[i]);
        }
        return max(maxNum, sum - minNum);
    }
};

image-20230910214024569

这里我们发现错误,我们分析一下,主要是总和以及较小和.我们发现他们相等.也就是差值为0,但是我们整个数组都是负数,不能出现这种情况,那么此时我们就要排除一些这个情况.

class Solution {
public:
    int maxSubarraySumCircular(vector<int>& nums) {
        if(nums.empty())
        return 0;
        int n = nums.size();
        vector<int> f(n+1, 0);
        vector<int> g(n+1, 0);
        int sum = 0;
        int maxNum =  INT_MIN;
        int minNum =  INT_MAX;
        for(int i = 1; i <= n; i++)
        {
            sum += nums[i-1];
            f[i] = std::max(f[i-1]+nums[i-1], nums[i-1]);
            maxNum = std::max(maxNum, f[i]);
            g[i] = std::min(g[i-1]+nums[i-1], nums[i-1]);
            minNum = std::min(minNum, g[i]);
        }
        if((sum - minNum) == 0)
        return maxNum;

        return max(maxNum, sum - minNum);
    }
};

image-20230910214245778

标签:最大,nums,int,环形,我们,vector,918,数组,LeetCode
From: https://blog.51cto.com/byte/7435494

相关文章

  • LeetCode/将石头分散到网格的最少移动次数
    给你一个大小为3*3,下标从0开始的二维整数矩阵grid,分别表示每一个格子里石头的数目。网格图中总共恰好有9个石头,一个格子里可能会有多个石头。每一次操作中,你可以将一个石头从它当前所在格子移动到一个至少有一条公共边的相邻格子。请你返回每个格子恰好有一个石头的......
  • #yyds干货盘点# LeetCode程序员面试金典:翻转二叉树
    题目:给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例1:输入:root=[4,2,7,1,3,6,9]输出:[4,7,2,9,6,3,1]示例2:输入:root=[2,1,3]输出:[2,3,1]示例3:输入:root=[]输出:[]代码实现:classSolution{publicTreeNodeinvertTree(TreeNoderoot){......
  • #yyds干货盘点# LeetCode程序员面试金典:第三大的数
    1.简述:给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。 示例1:输入:[3,2,1]输出:1解释:第三大的数是1。示例2:输入:[1,2]输出:2解释:第三大的数不存在,所以返回最大的数2。示例3:输入:[2,2,3,1]输出:1解释:注意,要求返回第三大的数,是指在所......
  • LeetCode209.长度最小的子数组
    9月8日LeetCode209.长度最小的子数组https://leetcode.cn/problems/minimum-size-subarray-sum/description/学习内容题目的内容是给一个正整数的数组及目标值target,找到大于等于目标值的连续数组最小长度的区间。容易想到的方法是两层for来遍历,分别表示区间终止位置和区间起始位......
  • Leetcode刷题本地debug框架搭建
    思路1.初版cmake+单一.cpp文件参考:https://blog.songjiahao.com/archives/3622.改良版cmake+源文件、头文件(含List、Tree等数据结构)分离+gtest参考:https://github.com/Pokerpoke/LeetCode Normal模板以Leetcode1两数之和为例#include<iostream>#include......
  • LeetCode刷题笔记
    算法1.差分数组+前缀和1589.所有排列中的最大和-力扣(LeetCode)对于每一次遍历都有m个数需要加1,如果对这些数遍历,则需要O(m)复杂度,此时可以记录这m个数的差分数组:​ 这样就可以把时间复杂度缩小到O(1),之后求前缀和就可以得到原来的数组。2.线性筛(欧拉筛)求素数2601.质数减法......
  • 代码随想录算法训练营第四天| 24. 两两交换链表中的节点, 19.删除链表的倒数第N个结点
    24.两两交换链表中的节点mydemo(超时)/***Definitionforsingly-linkedlist.*structListNode{*intval;*ListNode*next;*ListNode():val(0),next(nullptr){}*ListNode(intx):val(x),next(nullptr){}*ListNode(intx,Lis......
  • #yyds干货盘点# LeetCode程序员面试金典:用栈实现队列
    题目:请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):实现 MyQueue 类:voidpush(intx) 将元素x推到队列的末尾intpop() 从队列的开头移除并返回元素intpeek() 返回队列开头的元素booleanempty() 如果队列为空,返回 true ......
  • #yyds干货盘点# LeetCode程序员面试金典:等差数列划分
    1.简述:如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。例如,[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。子数组 是数组中的一个连续序列。 示例1......
  • [刷题记录Day 23]Leetcode二叉树
    No.1题目修剪二叉搜索树思路递归法有点抽象,要对具体案例做模拟才好懂递归分析返回值:节点,参数:节点,[下界,上界]终止条件:遇到空节点,返回空单层递归逻辑:判断不在范围内的情况:当前节点小于下界/大于上界,直接返回右/左子树递归结果;若在范围内,则递归筛查左右子树,返回当前节点......