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

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

相关推荐
星火开发设计2 小时前
枚举类 enum class:强类型枚举的优势
linux·开发语言·c++·学习·算法·知识
踩坑记录8 小时前
leetcode hot100 2.两数相加 链表 medium
leetcode·链表
qq_192779879 小时前
C++模块化编程指南
开发语言·c++·算法
代码村新手9 小时前
C++-String
开发语言·c++
历程里程碑11 小时前
滑动窗口---- 无重复字符的最长子串
java·数据结构·c++·python·算法·leetcode·django
2501_9403152612 小时前
航电oj:首字母变大写
开发语言·c++·算法
lhxcc_fly12 小时前
手撕简易版的智能指针
c++·智能指针实现
TracyCoder12312 小时前
LeetCode Hot100(18/100)——160. 相交链表
算法·leetcode
浒畔居12 小时前
泛型编程与STL设计思想
开发语言·c++·算法
Fcy64812 小时前
C++ 异常详解
开发语言·c++·异常