題目描述
輸入一個整型數組,數組裏有正數也有負數。數組中一個或連續的多個整數組成一個子數組。求所有子數組的和的最大值。要求時間負責度爲O(n)。
解析
1. 解法一:
看到這個題目,我們首先想到的是求出這個整型數組所有連續子數組的和,長度爲n的數組一共有 n(n+2)/2個子數組,因此要求出這些連續子數組的和最快也需要O(n^2)的時間複雜度。但是題目要求的O(n)的時間複雜度,因此上述思路不能解決問題。
2. 解法二:
看到O(n)時間複雜度,我們就應該能夠想到我們只能對整個數組進行一次掃描,在掃描過程中求出最大連續子序列和以及子序列的起點和終點位置。假如輸入數組爲{1,-2,3,10,-4,7,2,-5},我們嘗試從頭到尾累加其中的正數,初始化和爲0,第一步加上1,此時和爲1,第二步加上-2,此時和爲-1,第三步加上3,此時我們發現-1+3=2,最大和2反而比3一個單獨的整數小,這是因爲3加上了一個負數,發現這個規律以後我們就重新作出累加條件:如果當前和爲負數,那麼就放棄前面的累加和,從數組中的下一個數再開始計數。
3. 解法三:應用動態規劃法
主要代碼實現
int FindgGreatestOfSubArray(int* pData, int nLength){
//傳參有效性檢測
if(pData == NULL || nLength <= 0){
return 0;
}
int nCurSum = 0;
int nGreatestSum = 0;
for(int i=0; i<nLength; i++){
if(nCurSum < 0)
nCurSum = pData[i]; //拋棄i下標之前的數組元素
else
nCurSum += pData[i];
if(nCurSum > nGreatestSum)
nGreatestSum = nCurSum;
}
return nGreatestSum;
}
測試用例
// ====================測試代碼====================
void Test(char* testName, int* pData, int nLength, int expected, bool expectedFlag)
{
if(testName != NULL)
printf("%s begins: \n", testName);
int result = FindgGreatestOfSubArray(pData, nLength);
if(result == expected && expectedFlag == g_InvalidInput)
printf("Passed.\n");
else
printf("Failed.\n");
}
// 1, -2, 3, 10, -4, 7, 2, -5
void Test1()
{
int data[] = {1, -2, 3, 10, -4, 7, 2, -5};
Test("Test1", data, sizeof(data) / sizeof(int), 18, false);
}
// 所有數字都是負數
// -2, -8, -1, -5, -9
void Test2()
{
int data[] = {-2, -8, -1, -5, -9};
Test("Test2", data, sizeof(data) / sizeof(int), -1, false);
}
// 所有數字都是正數
// 2, 8, 1, 5, 9
void Test3()
{
int data[] = {2, 8, 1, 5, 9};
Test("Test3", data, sizeof(data) / sizeof(int), 25, false);
}
// 無效輸入
void Test4()
{
Test("Test4", NULL, 0, 0, true);
}
int main(void)
{
Test1();
Test2();
Test3();
Test4();
system("pause");
return 0;
}
改進
保存最大和對應的子數組:修改上面的主要代碼,當重置當前數組和的時候,記錄起始數組下標,修改數組最大值的時候,記錄當前最大值的數組下標。(在函數中採用引用傳遞參數,第一次使用引用變量)
int FindgGreatestOfSubArray(int* pData, int nLength, int& a, int& b){
//傳參有效性檢測
if(pData == NULL || nLength <= 0){
g_InvalidInput = true;
return 0;
}
int nCurSum = 0;
int nGreatestSum = 0;
for(int i=0; i<nLength; i++){
if(nCurSum < 0){
nCurSum = pData[i]; //拋棄i下標之前的數組元素
a = i;
}
else
nCurSum += pData[i];
if(nCurSum > nGreatestSum){
nGreatestSum = nCurSum;
b = i;
}
}
return nGreatestSum;
}