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 <= numsi <= 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)原题链接

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

相关推荐
rannn_1113 小时前
【力扣hot100】链表专题|160、206、234、141、142
java·算法·leetcode·链表·面试·开发
不会代码的小猴4 小时前
21. 泛型编程上
开发语言·c++·笔记·算法
营养充电站4 小时前
VS Code Git 工作树:解锁多分支并行开发的高效体验
leetcode·决策树·逻辑回归·散列表·模拟退火算法
青瓦梦滋5 小时前
传输层UDP/TCP协议
linux·网络·c++·网络协议·tcp/ip·udp
一只旭宝5 小时前
细讲C加加【9】C++ std::function与std::bind详解|仿函数、绑定器、类成员绑定、占位符、成员偏移指针
开发语言·c++·算法
良木林6 小时前
子串 - LeetCode hot 100
算法·leetcode·职场和发展
蒸蒸yyyyzwd6 小时前
秋招不熟悉力扣学习笔记1
笔记·学习·leetcode
Lhan.zzZ7 小时前
在 Visual Studio 2022 中打造可扩展的动态链接库模块:从零搭建到原理解析
开发语言·c++·visual studio
zh路西法9 小时前
【3D SLAM源码解读系列】(二)Small_gicp——5 个积木搭出最优点云配准
c++·pcl·icp·fastgicp·smallgicp·gicp
fpcc11 小时前
ubuntu26环境下的开发环境安装处理
c++·并行编程