LeetCode 面试经典 150_Kadane_环形子数组的最大和(110_918_C++_中等)(动态规划)

LeetCode 面试经典 150_Kadane_环形子数组的最大和(110_918_C++_中等)

题目描述:

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

输入输出样例:

示例 1:
输入 :nums = [-2,1,-3,4,-1,2,1,-5,4]
输出 :6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:
输入 :nums = [1]
输出:1

示例 3:
输入 :nums = [5,4,-1,7,8]
输出:23

提示:

1 <= nums.length <= 105

-104 <= nums[i] <= 104

题解:

解题思路:

思路一(动态规划):

0、在解决此问题时需用到一个结论(注意此处均表示子数组 ):
数组和(nums_sum) = 最大和(maxSum) + 最小和(minSum)
maxSum = nums_sum - minSum
因求 最大和 时 必定导致 其他元素 相加最小
通过此结论,可以直接求 最大和 或者 通过最小和来间接的求得最大和

1、在处理此问题时可分情况讨论:

  • 情况一 :最大和在数组内部,例 nums = [-1,-2,3,4,-5] ,其中 【3,4】为最大和
  • 情况二 :最大和在数组两侧,例 nums = [3 ,-1,-2,-5,4] ,其中 【3,4】为最大和
  • 情况三:全为负数,例 nums=[-1,-2,-3,-4,-5],其中【-1】为最大和

若为 情况一 遍历一遍数组只能 求得 最大和 ,和部分最小和

若为 情况二 遍历一遍数组只能 求得 最小和 ,和部分最大和 ,需通过maxSum = nums_sum - minSum 求得真实的 最大和

若为 情况三 遍历一遍数组只能 求得 最大和 ,且此时最小和为 0

2、复杂度分析:

① 时间复杂度:O(n),其中 n 是输入数组 nums 的长度,只进行了 一次遍历。

② 空间复杂度:O(1)。

代码实现

代码实现(思路一(动态规划)):
cpp 复制代码
class Solution {
public:
    int maxSubarraySumCircular(vector<int>& nums) {
        // 用来记录当前连续子数组的最大和
        int preMaxSum = 0;
        // 用来记录找到的最大子数组和
        int maxSum = INT_MIN;

        // 用来记录当前连续子数组的最小和
        int preMinSum = 0;
        // 用来记录找到的最小子数组和
        int minSum = 0;  

        // 用来记录所有元素的总和
        int nums_sum = 0;

        // 遍历输入数组
        for(int x : nums) {
            // 更新当前最大子数组和,若当前子数组和小于0则从新开始
            preMaxSum = max(preMaxSum, 0) + x;
            // 更新最大子数组和
            maxSum = max(preMaxSum, maxSum);

            // 更新当前最小子数组和,若当前子数组和大于0则从新开始
            preMinSum = min(preMinSum, 0) + x;
            // 更新最小子数组和
            minSum = min(preMinSum, minSum);

            // 累加元素到总和中
            nums_sum += x;
        }

        // 如果最大子数组和小于0,说明所有元素都是负数,返回最大子数组和
        // 否则返回最大值:最大子数组和 和 (总和 - 最小子数组和)
        return maxSum < 0 ? maxSum : max(maxSum, nums_sum - minSum);
    }
};
以思路一为例进行调试
cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;


class Solution {
public:
    int maxSubarraySumCircular(vector<int>& nums) {
        // 用来记录当前连续子数组的最大和
        int preMaxSum = 0;
        // 用来记录找到的最大子数组和
        int maxSum = INT_MIN;

        // 用来记录当前连续子数组的最小和
        int preMinSum = 0;
        // 用来记录找到的最小子数组和
        int minSum = 0;  

        // 用来记录所有元素的总和
        int nums_sum = 0;

        // 遍历输入数组
        for(int x : nums) {
            // 更新当前最大子数组和,若当前子数组和小于0则从新开始
            preMaxSum = max(preMaxSum, 0) + x;
            // 更新最大子数组和
            maxSum = max(preMaxSum, maxSum);

            // 更新当前最小子数组和,若当前子数组和大于0则从新开始
            preMinSum = min(preMinSum, 0) + x;
            // 更新最小子数组和
            minSum = min(preMinSum, minSum);

            // 累加元素到总和中
            nums_sum += x;
        }

        // 如果最大子数组和小于0,说明所有元素都是负数,返回最大子数组和
        // 否则返回最大值:最大子数组和 和 (总和 - 最小子数组和)
        return maxSum < 0 ? maxSum : max(maxSum, nums_sum - minSum);
    }
};

int main(int argc, char const *argv[])
{
    vector<int> nums={-2,1,-3,4,-1,2,1,-5,4};
    Solution s;
    cout<<s.maxSubarraySumCircular(nums);
    return 0;
}

LeetCode 面试经典 150_Kadane_环形子数组的最大和(110_918)原题链接

欢迎大家和我沟通交流(✿◠‿◠)

相关推荐
Z1Jxxx5 小时前
字符串翻转
开发语言·c++·算法
闻缺陷则喜何志丹5 小时前
【前缀和 期望】P7875 「SWTR-7」IOI 2077|普及+
c++·算法·前缀和·洛谷·期望
CSDN_RTKLIB5 小时前
ODR、linkage问题解惑
开发语言·c++
Sailing5 小时前
AI 流式对话该怎么做?SSE、fetch、axios 一次讲清楚
前端·javascript·面试
无限大65 小时前
为什么"缓存"能提高系统性能?——从 CPU 缓存到分布式缓存
后端·面试
非得登录才能看吗?5 小时前
C++多线程简单版(C++11 及以上)
c++
今儿敲了吗5 小时前
第二章 C++对C的核心拓展
c++·笔记
i建模5 小时前
C++和Rust的性能对比
开发语言·c++·rust
量子炒饭大师6 小时前
【C++入门】一名初级赛博神格的觉醒 —— 【什么是C++?】
c++·visualstudio·dubbo
Croa-vo6 小时前
Optiver OA 气球节模拟题:拆解系统建模的核心逻辑,附避坑指南
java·数据结构·算法·leetcode·职场和发展