1. 程式人生 > >劍指offer——連續子陣列的最大和(42題)

劍指offer——連續子陣列的最大和(42題)

題目:輸入一個整型陣列,數組裡有正數也有負數。陣列中的一個或連續多個整陣列成一個子陣列。求所有子陣列的和的最大值。要求時間複雜度為O(n)。

此題同時也是leetcode的原題。此處用兩種方法解答。方法一,叫不出名字,但只需一次遍歷,看程式碼很好理解。方法二,利用動態規劃,dp[i]中儲存以第i位置結尾的子序列的最大和。然後最後再求dp中的最大值。方法二的求解複雜度可能會稍高些,但不失為一種方法。

注意:以下程式碼均沒有考慮特殊值輸入的條件。如果需要,其思想是,應該設定一個全域性變數,一旦檢測出輸入陣列錯誤時,需要修改全域性變數後才返回函式(這一步驟省略了,不好意思)。

方法一程式碼:

int maxSumOfSubarray1(vector<int>& nums) {
	int curSum = 0, ret = (int)0x80000000;
	for (int i = 0; i < nums.size(); ++i) {
		curSum += nums[i];
		ret = (curSum > ret ? curSum : ret);//這一步隱含:子序列的最後一位數字絕不可能是負值
		if (curSum < 0)
			curSum = 0;
	}
	return ret;
}

方法二:

//利用動態規劃思想 /*  f(i)表示以第i個數字結尾的子陣列的最大和  當i=0或者f(i-1)<=0, f(i)=nums[i]  當f(i-1)<=0時,f(i)即為第i+1個數字本身  當f(i-1)>0,f(i)=f(i-1)+nums[i]   當f(i-1)>0時,f(i)即為以第i-1個數字結尾的子陣列中所有數字的和與第i個數字累加所得結果 */

程式碼如下:

int maxSumOfSubarray2(vector<int>& nums) {
	vector<int> dp(nums.size(), 0);
	dp[0] = nums[0];
	for (int i = 1; i < nums.size(); ++i) {
		if (dp[i - 1] <= 0)
			dp[i] = nums[i];
		else
			dp[i] = dp[i - 1] + nums[i];
	}
	vector<int>::iterator it = max_element(dp.begin(), dp.end());
	return *it;
}

驗證程式碼:

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;


int main() {
	vector<int> nums = { 1,-2,3,10,-4,7,2,-5 };
	int ret1,ret2;
	ret1 = maxSumOfSubarray1(nums);
	ret2 = maxSumOfSubarray2(nums);
	return 0;
}