c 最大子序列和_最大子序列和暴力法、分治+递归法、妙法
生活随笔
收集整理的這篇文章主要介紹了
c 最大子序列和_最大子序列和暴力法、分治+递归法、妙法
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
你好,我是goldsunC
讓我們一起進(jìn)步吧!
最大子序列和
Question:給定整數(shù)(可能有負(fù)數(shù)),求的最大值(為方便起見,如果所有整數(shù)均為負(fù)數(shù),則最大子序列和為0)。
示例:IN????:???[-2,11,-4,13,-5,-2]OUT????:???20??即從A2-A4
暴力求解
第一種思路很簡(jiǎn)單,暴力求解。從數(shù)組第一個(gè)整數(shù)開始遍歷每一種長(zhǎng)度的最大值,然后遍歷之后的最大值即是最大子序列和,如果最大值為負(fù)數(shù)則初始化為0,例如:指定數(shù)組為:[-2,11,-4,13,-5,-2]首先初始化最大值為-2,因?yàn)?2為負(fù)數(shù)所以最大值為0,然后計(jì)算-2+11,然后更新最大值為9,然后計(jì)算-2+11-4,保持當(dāng)前最大值,然后計(jì)算-2+11-4+13,更新最大值為18,一直加到數(shù)組最后一位數(shù),再?gòu)?1開始求最大值,然后再?gòu)?4開始,就這樣把數(shù)組每一種子序列和都遍歷了,求得最大值。源碼(Java):public?class?maxValueSum?{????public?static?void?main(String[]?args)?{
????????int[]?array?=?{-2,11,-4,13,-5,-2};
????????System.out.println(Max(array));
????}
????public?static?int?Max(int[]?array)?{
????????int?maxnum?=?array[0];
????????for?(int?i=0;i????????????int?currentnum?=?0;
????????????for?(int?j=i;j????????????????currentnum?+=?array[j];
????????????????if?(currentnum>maxnum)
????????????????????maxnum?=?currentnum;
????????????}
????????}
????????return?maxnum;
????}
}
源碼(Python):def?Max(array)?:
????maxnum?=?0
????for?i?in?range(len(array)):
????????num?=?0
????????for?j?in?range(i,len(array)):
????????????num?+=?array[j]
????????????if?num?>?maxnum:
????????????????maxnum?=?num
????return?maxnum
array?=?[-2,11,-4,13,-5,-2]
print(Max(array))
上面暴力求解法很簡(jiǎn)單,但是有個(gè)突出的問(wèn)題,就是時(shí)間復(fù)雜度為O(),當(dāng)涉及到大量輸入的時(shí)候,效率非常低。
分治+遞歸求解
通常來(lái)講,我們遇見遞歸的時(shí)候往往伴隨的還有很高的時(shí)間復(fù)雜度,但對(duì)于這個(gè)問(wèn)題來(lái)講還有一個(gè)使用遞歸+分治實(shí)現(xiàn)的稍微復(fù)雜的方法,其時(shí)間復(fù)雜度卻僅為O(),或許這個(gè)算法就是體現(xiàn)遞歸為例的最好范例了。這個(gè)算法使用一種"分治"的策略,其想法是把問(wèn)題分成兩個(gè)大致相等的子問(wèn)題,然后采用遞歸對(duì)他們求解,這是分,治是將兩個(gè)子問(wèn)題的解合并到一起并再做些少量的附加工作,最后得到整個(gè)問(wèn)題的解。假如將傳入的數(shù)組從中間分成左右兩個(gè)部分,例如:[-2,11,-4,13,-5,-2]->[-2,11,-4]和[13,-5,-2]那么問(wèn)題的解可能出現(xiàn)在三處出現(xiàn):左半部分[-2,-11,-4]
右半部分[13,-5,-2]
或者橫跨兩個(gè)部分,它一定包括左半部分的最后一個(gè)值和右半部分的第一個(gè)值。
????public?static?void?main(String[]?args)?{
????????//?初始化數(shù)組
????????int[]?array?=?{-2,11,-4,13,-5,-2};
????????System.out.println(maxSum(array,0,array.length-1));
????}
????/**
?????*?遞歸求解函數(shù)
?????*?@param?array :傳入要解決的數(shù)組
?????*?@param?left ?:要解決子問(wèn)題的左界
?????*?@param?right :要解決子問(wèn)題的右界
?????*?@return??:返回三個(gè)部分的最大值
?????*/
????public?static?int?maxSum(int[]?array,int?left,int?right)?{
????????//?? BASE情況,如果遞歸到了最后一層,那么返回合適的值,小于0返回0,大于0返回該數(shù)。
????????if(left?==?right)?{
????????????if?(array[left]?>?0)
????????????????return?array[left];
????????????else?return?0;
????????}
????????int?center?=?(left+right)/2;????//??取得數(shù)組中點(diǎn)
????????int?leftSubSUM?=?maxSum(array,left,center);?????//??子問(wèn)題左半部分最優(yōu)解
????????int?rightSubSUM?=?maxSum(array,center+1,right);?????//??子問(wèn)題右半部分最優(yōu)解
????????int?leftNowSum?=?0,?maxleftSum?=?0;?????//??當(dāng)前問(wèn)題左半部分等待求和的當(dāng)前值以及最大值
????????//??遍歷求包含左半部分最后一個(gè)值的最大值
????????for?(int?i=center;i>=left;i--)?{
????????????leftNowSum?+=?array[i];
????????????if?(leftNowSum?>?maxleftSum)?{
????????????????maxleftSum?=?leftNowSum;
????????????}
????????}
????????int?rightNowSum?=?0,maxrightSum?=?0;????//??當(dāng)前問(wèn)題右半部分等待求和的當(dāng)前值以及最大值
????????//??遍歷求包含右半部分的第一個(gè)值的最大值
????????for?(int?j=center+1;j<=right;j++)?{
????????????rightNowSum?+=?array[j];
????????????if?(rightNowSum>maxrightSum)?{
????????????????maxrightSum?=?rightNowSum;
????????????}
????????}
????????//??返回當(dāng)前問(wèn)題的左半部分最大值、右半部分的最大值和橫跨兩部分最大值的最大值。即為當(dāng)前問(wèn)題的解。
????????return?Math.max(Math.max(leftSubSUM,rightSubSUM),(maxleftSum+maxrightSum));
????}
}
源碼(Python):def?maxSUM(array,left,right):
????if?left==right:
????????if?array[left]?>?0:
????????????return?array[left]
????????else:
????????????return?0
????center?=?int((left+right)/2)
????leftSubSUM?=?maxSUM(array,left,center)
????rightSubSUM?=?maxSUM(array,center+1,right)
????leftNowNum,maxleftSum?=?0,0
????for?i?in?reversed(range(left,center+1)):
????????leftNowNum?+=?array[i]
????????if?leftNowNum?>?maxleftSum:
????????????maxleftSum?=?leftNowNum
????rightNowNum,maxrightSum?=?0,0
????for?i?in?range(center+1,right+1):
????????rightNowNum?+=?array[i]
????????if?rightNowNum?>?maxrightSum:
????????????maxrightSum?=?rightNowNum
????return?max(leftSubSUM,rightSubSUM,maxleftSum+maxrightSum)
if?__name__?==?'__main__':
????array?=?[-2,11,-4,13,-5,-2]
????print(maxSUM(array,0,len(array)-1))
兩個(gè)程序的原理相同,運(yùn)行正確,不過(guò)鄙人水平有限,如果各位發(fā)現(xiàn)有問(wèn)題還煩請(qǐng)指出,謝謝!這個(gè)算法稍微復(fù)雜一點(diǎn),程序更長(zhǎng)一點(diǎn),不過(guò)時(shí)間復(fù)雜度只有O(),相比O()已經(jīng)好了很多,不過(guò)事實(shí)上還有一種更加有效且巧妙的算法。
算法3
這個(gè)算法我也不清楚它的名字,不過(guò)它確是最好的,首先看源代碼:源碼(Java):public?class?maxValueSum3?{????public?static?void?main(String[]?args)?{
????????int[]?array?=?{-2,11,-4,13,-5,-2};
????????System.out.println(maxSubSum(array));
????}
????public?static?int?maxSubSum(int?[]?array)?{
????????int?maxSum?=?0,NowSum?=?0;
????????for?(int?i?=?0;?i?????????????NowSum?+=?array[i];
????????????if?(NowSum?>?maxSum)
????????????????maxSum?=?NowSum;
????????????else?if?(NowSum?0)
????????????????NowSum?=?0;
????????}
????????return?maxSum;
????}
}
源碼(Python):def?maxSubSum(array):
????maxSum,NowSum?=?0,0
????for?i?in?range(len(array)):
????????NowSum?+=?array[i]
????????if?NowSum?>?maxSum:
????????????maxSum?=?NowSum
????????elif?NowSum?0:
????????????NowSum?=?0
????return?maxSum
if?__name__?==?'__main__':
????array?=?[-2,11,-4,13,-5,-2]
????print(maxSubSum(array))
代碼很短,不過(guò)要想清楚原理可能比之前都稍微難點(diǎn)。它是正確可行的,并且不難看出時(shí)間復(fù)雜度為O(N),它的效率很高,不過(guò)到底是怎么實(shí)現(xiàn)的呢?那寧哥我就用蹩腳的話來(lái)簡(jiǎn)單分享下我的理解吧。首先可以看到,該算法只是簡(jiǎn)單遍歷了一遍數(shù)組而已,就找到了最大子序列和。為什么可以這樣?首先,任何負(fù)的子序列不可能是最優(yōu)子序列的前綴。除非數(shù)組中的所有值均為負(fù)數(shù),只要有一個(gè)正數(shù),那么最優(yōu)子序列的和的前綴一定不可能是負(fù)數(shù)。因此這也就說(shuō)明了代碼中的else if(NowSum<0) NowSUm=0;了,也就是如果當(dāng)前子序列的和為負(fù)值,那么初始化為0,它已經(jīng)不可能是最有子序列的前綴了,就把它的記錄拋棄了,如果當(dāng)前位置在N,那問(wèn)題就變成了求array[N+1]-array[array.length-1]的最有子序列了。然后還有一個(gè)判斷語(yǔ)句if(NowSum > maxSum) maxSum = thisSum;,看起來(lái)很簡(jiǎn)單,意思就是如果當(dāng)前子序列和大于記錄的最大值,那就更新。可如果放到整個(gè)程序里如何保證能正確運(yùn)行呢?對(duì)一個(gè)子序列,如果是每一個(gè)數(shù)都遞增或者遞減比較好理解,遞增的話最大子序列值就是從第一個(gè)大于0的數(shù)開始到整個(gè)序列,如果是遞減的話就是第一個(gè)數(shù)開始到第一個(gè)小于等于0之前的那個(gè)數(shù)。還有兩種情況,子序列整體遞增或整體減小,但是數(shù)大大小小不確定。如果子序列整體是增加的,也好理解,仍然是整個(gè)序列值唄,那如果子序列是整體遞減呢?如果整體是遞減的,說(shuō)明剛開始某個(gè)地方會(huì)有一個(gè)最大值,那樣的話我們的方法在剛開始就已經(jīng)把序列最大值記錄了,后面只是更新而已,哈哈哈突然解決。明白了嗎?
???end???
走在路上
goldsunC
總結(jié)
以上是生活随笔為你收集整理的c 最大子序列和_最大子序列和暴力法、分治+递归法、妙法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: springboot 按钮权限验证_Sp
- 下一篇: mysql索引_mysql系列:深入理解