一、問題描述
輸入乙個整形陣列,陣列裡可以有正數或負數。陣列中連續的乙個或多個整數組成乙個子陣列,每個子陣列都有乙個和。求所有子陣列的和的最大值。要求時間複雜度為o(n)。
例如輸入的陣列為1, -2, 3, 10, -4, 7, 2, -5,和最大的子陣列為3, 10, -4, 7, 2,因此輸出為該子陣列的和18。
第一次遇到這道題是參加x迅的筆試。題目中給出了兩種解法,讓填空。
二、簡單解
拿到這道題,如果不考慮效能和複雜度,最簡單的方法就是窮舉。窮舉出所有的子陣列,並求出他們的和,返回最大值。不過,複雜度為o(n3),不符合題目的要求(複雜度on)
[cpp] view plaincopyprint?
int max_sum(int *arr, int len)
} }
} if(max == 0)
return max;
} int max_sum(int *arr, int len)
}} }
if(max == 0)
return max;
}三、複雜度為n2的解
觀察上面的**,我們使用了3個for迴圈。其中最內側的for迴圈主要是控制每個字序列的長度,由於我們在計算的過程中,已經儲存了當前最大字序列和,字序列的長度n對我們來說意義不大,因此完全可以撤消最內側的迴圈。只按每個字序列起始位置來計算最大和。這樣得到乙個複雜度為n2的解。
[cpp] view plaincopyprint?
int max_sum2(int *arr, int len)
} }
if(max == 0)
return max;
} int max_sum2(int *arr, int len)
} }if(max == 0)
return max;
}四、更低複雜度的探索
至此,我們已經得到乙個複雜度為n2的解法。那麼有沒有更低複雜度的演算法呢?在n2的演算法中,我們遍歷了從0到len-1開始的字序列,求出每種情況下得到的最大字序列和。那麼我們有沒有可能去掉這個迴圈呢?考慮使用動態規劃的思想,記max_sum[i]為從0到i的子串行的最大和,那麼可以得到遞推式:
[cpp] view plaincopyprint?
if max_sum[i] > 0
then
if arr[i+1] > 0
then max_sum[i+1] = max_sum[i] + arr[i+1];
else
max_sum[i+1] = max(0, arr[i+1])
if max_sum[i] > 0
then
if arr[i+1] > 0
then max_sum[i+1] = max_sum[i] + arr[i+1];
else
max_sum[i+1] = max(0, arr[i+1])
利用這種思路得到乙個線性時間的解答:
[cpp] view plaincopyprint?
int max_sum3(int *arr, int len)
if(sum > max)
} if(max == 0)
return max;
} int max_sum3(int *arr, int len)
if(sum > max)
} if(max == 0)
return max;
}至此,我們得到乙個時間複雜度on,空間複雜度o1的解。
求陣列子串行的最大和
輸入乙個整形陣列,陣列裡可以有正數或負數 陣列中連續的乙個或多個整數組成乙個子陣列,每個子陣列都有乙個和。求所有子陣列的和的最大值。要求 時間複雜度為o n 例如輸入的陣列為1,2,3,10,4,7,2,5,和最大的子陣列為3,10,4,7,2,因此輸出為該子陣列的和18。第一次遇到這道題是參加x迅...
求陣列非連續子串行的最大和
題目描述 1.乙個整數陣列l,如 l 2,3,3,50 求 l的乙個非連續子串行,使其和最大,輸出最大子串行的和。這裡非連續子串行的定義是,子串行中任意相鄰的兩個數在原序列裡都不相鄰。例如,對於 l 2,3,3,50 輸出 52 分析 很明顯,該列表最大非連續子串行為 2,50 測試例子 l 2,3...
求陣列中連續子陣列的最大和
思路 計算出任意i到j之間連續子陣列的和再比較必然能得到最大值,但時間複雜度為o n 2 我們希望能找出線性時間的演算法。我們注意到,假如陣列中全為正數,那麼最大和必然為全部數相加 如果陣列中有負數,並且如果加上某個負數,子陣列的和小於0,則最大和子陣列必然不包含這個負數。基於此,給出以下 incl...