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

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

相关推荐
张健115640964813 小时前
C++访问控制与友元
java·开发语言·c++
水蓝烟雨13 小时前
3337. 字符串转换后的长度 II
算法·leetcode
_日拱一卒14 小时前
LeetCode:226翻转二叉树
数据结构·算法·leetcode
踩坑记录14 小时前
leetcode hot100 64. 最小路径和 medium 递归优化
leetcode·深度优先
BirdenT14 小时前
20260424紫题训练
c++·算法
还是阿落呀14 小时前
基本控制结构
开发语言·c++·算法
禧西14 小时前
面试准备——agent和大模型
面试·职场和发展
样例过了就是过了14 小时前
LeetCode热题100 最长有效括号
c++·算法·leetcode·动态规划
南境十里·墨染春水14 小时前
C++笔记 forward完美转发
开发语言·c++·笔记
吃着火锅x唱着歌14 小时前
深度探索C++对象模型 学习笔记 第四章 Function语意学(2)
c++·笔记·学习