力扣剑指 Offer 42. 连续子数组的最大和(字节一面)

本文介绍了如何使用贪心算法和动态规划解决寻找整型数组中最大子数组和的问题,两种方法的时间复杂度均为O(n)。在贪心算法中,通过维护当前子数组的和sum及最大值max,当sum小于0时重置为0;而在动态规划中,通过dp数组记录每个位置的最大和,最后返回maxSum作为结果。动态规划的优化版进一步减少了空间复杂度到O(1)。
摘要由CSDN通过智能技术生成

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

 

方法一:贪心算法

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        /*此处的代码是因为题目给出了提示,1 <= arr.length <= 10^5,即nums数组大小的范围
        if (nums.size() == 1) {
			return nums[0];
		}
        */
        //如果数组的大小为0,直接返回0即可
        if (nums.size() == 0) {
			return 0;
		}
		int sum = 0;
		int max = INT_MIN;//由于我们求的是最大值,所以给max初始值赋为INT_MIN
        //遍历整个nums数组,用sum记录当前子数组的和
		for (int i = 0; i < nums.size(); i++) {
			sum += nums[i];
            //如果sum比max大,则更新max的值
			if (sum > max) {
				max = sum;
			}
            //由于sum记录的是当前子数组的和,如果<0,直接将sum赋为0,因为如果sum<0,不论下一个待遍历的数是正数还是负数,都影响我求所有子数组的和的最大值
			if (sum < 0) {
				sum = 0;
			}
		}
		return max;
    }
};

方法二:动态规划

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int n=nums.size();
        //首先判断nums的大小,如果nums的长度为1,我们直接返回nums数组中唯一的那个元素即可
        if(n==1){
            return nums[0];
        }
        //创建dp数组,dp[i]表示当前遍历到位置i的最大和
        vector<int> dp(n);
        dp[0]=nums[0];        //初始化dp数组
        int maxSum=nums[0];   //maxSum用来记录整个数组中连续子数组的最大和
        for(int i=1;i<n;++i){
            dp[i]=max(dp[i-1]+nums[i],nums[i]);  //nums[i]比dp[i-1]+nums[i]大的情况,说明dp[i-1]是一个负数
            maxSum=max(maxSum,dp[i]);   //始终保持maxSum为dp数组中最大的元素
        }
        return maxSum;
    }
};

时间复杂度:O(n)n为数组nums的长度

空间复杂度:O(n)n为数组nums的长度

动态规划的优化

由于我们只需要知道当前遍历到的i位置的前一个位置(i-1)的最大和,就可以确定当前i位置的最大和应该为多少,所以我们无需创建dp数组,来记录每一个位置的最大和是多少,只需要一个变量pre,来记录当前遍历到的i位置的前一个位置i-1处的最大和即可,pre要保持更新

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int n=nums.size();
        //先判断nums数组的长度,根据提示1 <= nums.length <= 105,我们知道nums数组的最小长度为1
        //如果nums数组的长度为1,我们直接返回数组中唯一的这个元素
        if(n==1){
            return nums[0];
        }
        int maxSum=nums[0];      //maxSum用来记录最大和
        int pre=nums[0];         //pre表示当前遍历到元素的上一个位置的最大和
        int cur=0;               //cur表示当前遍历到元素位置的最大和,由于还未开始遍历,所以先初始化为0
        for(int i=1;i<n;++i){
            cur=max(pre+nums[i],nums[i]); //当nums[i]比pre+nums[i]大的时候,说明pre是一个负数
            pre=cur;                        //更新pre,令它为当前遍历到元素位置的最大和(假设当前i=1,pre就更新为位置1的最大和),因为下次for循环进来的时候,pre就代表上一次记录的结果了(下次i=2的时候,需要参考i=1时的最大和)
            maxSum=max(maxSum,cur); 
        }
        return maxSum;           //将记录的最大和返回即可
    }
};

时间复杂度:O(n)n为数组nums的长度

空间复杂度:O(1)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值