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

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

相关推荐
想用offer打牌3 小时前
高并发下如何保证接口的幂等性
后端·面试·状态机
牛奶15 小时前
Vue 基础理论 & API 使用
前端·vue.js·面试
牛奶15 小时前
Vue 底层原理 & 新特性
前端·vue.js·面试
NAGNIP16 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
青青家的小灰灰21 小时前
深入理解事件循环:异步编程的基石
前端·javascript·面试
程序员清风1 天前
程序员兼职必看:靠谱软件外包平台挑选指南与避坑清单!
java·后端·面试
端平入洛1 天前
delete又未完全delete
c++
UrbanJazzerati1 天前
Vue3 父子组件通信完全指南
前端·面试
UrbanJazzerati1 天前
Vue 3 纯小白快速入门指南
前端·面试
NAGNIP2 天前
轻松搞懂全连接神经网络结构!
人工智能·算法·面试