剑指 Offer 42. 连续子数组的最大和

文章整理自lc题解,仅供本蒟蒻复习参考,若涉嫌侵权,请联系本蒟蒻删除。

题目描述

剑指 Offer 42. 连续子数组的最大和

解法1:动态规划

以某个数作为结尾,意思是这个数一定要加上去,那么要看的就是这个数前面的部分要不要加上去,大于0就加,否则就不加。

// 基本动态规划  时间复杂度O(n), 空间复杂度O(n) 
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        // 动态规划
		// 状态定义:dp[i] 表示以 nums[i] 结尾的连续子数组的最大和
		// 状态转移方程:
		// (1) 如果 dp[i - 1] > 0, dp[i] = dp[i - 1] + nums[i] ;
		// (2) 如果 dp[i - 1] <= 0, dp[i] = nums[i]。 
		int len = nums.size(), ans = nums[0];
		if (len == 0) {
			return 0;
		}
		
		int dp[len];
		dp[0] = nums[0];
		
		for (int i = 1; i < len; i++) {
			if (dp[i - 1] > 0) {
				dp[i] = dp[i - 1] + nums[i];
			} else {
				dp[i] = nums[i];
			}
			
			ans = max(dp[i], ans);
		}
		
		return ans;
    }
};

利用滚动数组优化

考虑到dp[i] 只与 dp[i - 1] 有关,因此我们可以只用一个变量 dp 来维护。

// 利用滚动数组优化 时间复杂度O(n),空间复杂度O(1) 
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
    	// 考虑到dp[i] 只与 dp[i - 1] 有关,因此我们可以只用一个变量 dp 来维护。 
       	int dp = nums[0], ans = nums[0];
       	for (int i = 1; i < nums.size(); i++) {
       		dp = max(nums[i], nums[i] + dp);
       		ans = max(ans, dp);
       	}
        return ans;
    }
};

解法2:前缀和

前缀和详解:林小鹿@ 前缀和与差分 图文并茂 超详细整理(全网最通俗易懂)
在一次遍历中,记录当前遍历到的最小前缀和,此最小前缀和一定为连续子数组的最大和的左边界。每次遍历都能得到一个右边界,与之前的最小前缀和相减,即可得到一个连续子数组的和,取最大值即为连续子数组的最大和。

// 前缀和 时间复杂度O(n),空间复杂度O(1) 
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
    	int min = 0, ans = -2147483648, sum = 0;
    	for (int i = 0; i < nums.size(); i++) {
    		sum += nums[i];
    		ans = max(ans, sum - min);
    		// 记录当前所遍历到的最小前缀和,就能确保最终的结果一定是以该最小的前缀和为左边界
			// 因此在一次遍历中,就可以得到每个右边界和之前的最小前缀和的左边界的差值,即子数组元素和 
    		if (sum < min) {
    			min = sum;
    		}
    	}
    	return ans;
    }
};

你可能感兴趣的:(Algorithms,算法,leetcode,动态规划)