leetcode 3640. 三段式数组 II 困难

给你一个长度为 n 的整数数组 nums

三段式子数组 是一个连续子数组 nums[l...r](满足 0 <= l < r < n),并且存在下标 l < p < q < r,使得:

  • nums[l...p] 严格 递增,
  • nums[p...q] 严格 递减,
  • nums[q...r] 严格 递增。

请你从数组 nums 的所有三段式子数组中找出和最大的那个,并返回其 最大和。

示例 1:

**输入:**nums = 0,-2,-1,-3,0,2,-1

输出:-4

解释:

选择 l = 1, p = 2, q = 3, r = 5

  • nums[l...p] = nums[1...2] = [-2, -1] 严格递增 (-2 < -1)。
  • nums[p...q] = nums[2...3] = [-1, -3] 严格递减 (-1 > -3)。
  • nums[q...r] = nums[3...5] = [-3, 0, 2] 严格递增 (-3 < 0 < 2)。
  • 和 = (-2) + (-1) + (-3) + 0 + 2 = -4

示例 2:

输入: nums = 1,4,2,7

输出: 14

解释:

选择 l = 0, p = 1, q = 2, r = 3

  • nums[l...p] = nums[0...1] = [1, 4] 严格递增 (1 < 4)。
  • nums[p...q] = nums[1...2] = [4, 2] 严格递减 (4 > 2)。
  • nums[q...r] = nums[2...3] = [2, 7] 严格递增 (2 < 7)。
  • 和 = 1 + 4 + 2 + 7 = 14

提示:

  • 4 <= n = nums.length <= 10^5
  • -10^9 <= nums[i] <= 10^9
  • 保证至少存在一个三段式子数组。

分析:先预处理出 nums 数组的前缀和数组 sum。遍历 nums,令 f 代表当前的变化状态,其中 f=0 时为初始情况,f=1 代表之前为递增序列,f=-1 代表递减序列;令 cnt 代表当前是第几段;令 ind1 代表第一段的开始下标,ind2 代表第二段的开始下标,ind3 代表第三段的开始下标。

遍历时,根据 numsi 与 numsi-1 的大小关系,判定当前应该属于第几段数组。注意当数组出现递增时,需要判断是否之前已经出现过三段,如果是,则将原来的第三段变成新的第一段。当出现了三段数组后,根据前缀和计算这三段数组的和。求和时,注意第一段的开始可能为负数,可以去掉,此时 ind1 增大,同时第三段的末尾可能为负,也可以去掉,此时 ind3 减小。

cpp 复制代码
long long max(long long a,long long b)
{
    return a>b?a:b;
}
long long maxSumTrionic(int* nums, int numsSize) {
    long long sum[numsSize+5];sum[0]=nums[0];
    for(int i=1;i<numsSize;++i)
        sum[i]=0,sum[i]=sum[i-1]+nums[i]*1LL;

    int cnt=0,f=0,ind1=0,ind2=0,ind3=0;
    long long ans=-1e14;
    for(int i=1;i<numsSize;++i)
    {
        if(nums[i]==nums[i-1])cnt=0,f=0,ind1=i,ind2=ind3=0;
        else if(nums[i]>nums[i-1])
        {
            if(f!=1)cnt++,f=1;
            if(cnt==3&&!ind3)ind3=i;
        }
        else
        {
            if(f==1)
            {
                f=-1,cnt++,ind2=i;
                if(cnt==4)
                {
                    cnt=2,ind1=ind3-1,ind3=0;
                    while(ind1+2<i&&nums[ind1]<0)ind1++;
                }
            }
            if(f!=-1)cnt=0,ind1=i,ind2=ind3=0;
        }

        if(cnt==3)
        {
            while(ind1+2<ind2&&nums[ind1]<0)ind1++;

            long long temp=sum[i];
            if(ind1>0)temp-=sum[ind1-1];
            ans=max(ans,temp);
        }
    }

    return ans;
}
相关推荐
To_OC12 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
旖-旎14 小时前
LeetCode 518:零钱兑换||(完全背包)—— 题解
c++·算法·leetcode·动态规划·背包问题
To_OC14 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
tachibana21 天前
hot100 数组中的第K个最大元素(215)
java·数据结构·算法·leetcode
晚笙coding1 天前
LeetCode 98:验证二叉搜索树 —— 从局部判断到全局范围约束的递归思想
算法·leetcode·职场和发展
兰令水1 天前
hot100【acm版】【2026.7.21打卡-java版本】
java·开发语言·算法·leetcode·面试
退休倒计时1 天前
【每日一题】LeetCode 131. 分割回文串 TypeScript
算法·leetcode·typescript
旖-旎2 天前
LeetCode 279:完全平方数(完全背包)—— 题解
c++·算法·leetcode·动态规划·背包问题
良木林2 天前
滑动窗口 - LeetCode hot 100
javascript·算法·leetcode·双指针·滑动窗口
晚笙coding2 天前
LeetCode 108:将有序数组转换为二叉搜索树 —— 从数组到平衡二叉树的递归构造
数据结构·算法·leetcode