日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

最大子列和问题(JAVA)

發布時間:2025/3/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 最大子列和问题(JAVA) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最大子列和

問題描述:給定N個整數的序列{A1,A2,A3,…,An},求解子列和中最大的值。

這里我們給出{-2,11,-4,13,-5,-2}這樣一個序列,正確的最大子列和為20

該題是在數據結構與算法中經常用于分析時間復雜度的典型題目,以下將給出四種方法來求解


一、三層循環——窮舉法

(時間復雜度O(N^3))
這種方法的思路就是將每一個子列和都求出來,然后找出最大子列和

public static int maxSubSum1(int[] arr){//設置整體最大值int maxSum = 0;//窮舉法遍歷//循環大小:Nfor( int i = 0;i<arr.length;i++ ){//循環大小:N-ifor(int j = i;j<arr.length;j++){//設置當前最大值int thisSum = 0;//求解arr[i]~arr[j]的最大值//循環大小:j-i+1for(int k = i;k<=j;k++){thisSum += arr[k];}//更新最大值if(thisSum > maxSum){maxSum = thisSum;}}}return maxSum;}

這種做法包含了三個循環,第一個循環的大小為N,第二個循環的大小為N-i,第三個循環的大小為j-i+1,根據時間復雜度的計算方法我們這里都可以看成N,所以時間復雜度為O(n^3)

二、兩層循環——窮舉法優化

(時間復雜度O(N^2))

這種算法是對以一種情況的優化,但是仍然屬于窮舉法,示例圖和第一種方法一樣,這里不再重復給出。

public static int maxSubSum2(int[] arr){//設置整體最大值int maxSum = 0;//窮舉法遍歷//循環大小Nfor(int i = 0;i < arr.length;i++){int thisSum = 0;//循環大小N-ifor(int j = i;j<arr.length;j++){//直接進行累加,改進不必要的第三重循環thisSum += arr[j];if( thisSum > maxSum ){maxSum = thisSum;}}}return maxSum;}

觀察第一種方法我們可以發現,第三層循環雖然盡可能優的列出了所有的情況,但是這種做法是可以進行優化的,按照問題描述,如果我們去除第三重循環,仍然可以實現窮舉所有的情況,算法的時間復雜度變為O(n^2)

三、分治思想——遞歸法

(時間復雜度O(N·logN))

分治思想(divide-and-conquer)的基本思路是:把問題分成兩個大致相等的子問題,然后遞歸地對它們求解,這是“分”的思想;“治”階段將兩個子問題的解修補到一起并可能再做些少許的附加工作,最后得到整個問題的解。

通過這種思想,最大子列和有可能出現在三個地方,左半段、右半段、交界處。
前兩種情況可以通過遞歸求解,而第三種情況需要求出左半段帶邊界(即含有最后一個元素)的最大和以及右半段帶邊界(即含有第一個元素)的最大和而得到。

本題中,將序列從中間分開,分別求兩部分的最大值。由此可見左邊最大的為11,右邊最大的為13,而交界處最大和需要通過左半段帶邊界的最大和,與右半段帶邊界的最大和,求和。(此處不易理解,讀者可以根據圖示中的綠色部分輔助理解,圖中的綠色部分就是符合交界處序列和的值,左邊最大值為7,右邊最大值為13,和為20),綜上比較,該序列的最大序列和為20

public static int maxSubSum3(int[] arr){//將數組arr,數組的下限0,數組的上限arr.length-1傳入遞歸函數return maxSubSumRec(arr,0,arr.length-1);}//遞歸函數private static int maxSubSumRec(int[] arr,int left,int right){//當 left==right 時說明只有一個元素,并且當該元素非負時就是他的最大子序列if(left == right){if(arr[left] > 0){return arr[left];}else {return 0;}}//遞歸定義部分int center = ( left + right) / 2;int maxLeftSum = maxSubSumRec(arr,left,center);int maxRightSum = maxSubSumRec(arr,center+1,right);//遞歸實現部分int maxLeftBorderSum = 0;int leftBorderSum = 0;for(int i = center;i>=left;i--){leftBorderSum += arr[i];if(leftBorderSum > maxLeftBorderSum){maxLeftBorderSum = leftBorderSum;}}int maxRightBorderSum = 0;int rightBorderSum = 0;for(int i = center + 1;i<=right;i++){rightBorderSum += arr[i];if(rightBorderSum > maxRightBorderSum){maxRightBorderSum = rightBorderSum;}}//判斷三者大小return max3(maxLeftSum,maxRightSum,maxLeftBorderSum + maxRightBorderSum);}//比較函數public static int max3(int a,int b,int c){int max;if(a>b){max = a;}else {max = b;}if(max>c){return max;}else {return c;}}

注:我們需要保存的不僅是左右兩側的最大序列和,還需要得到左右兩側帶邊界的最大序列和,這也就是為什么左側循環從center往前遍歷,而右側循環從center+1往后遍歷的原因,此順序不可顛倒

這種方法乍看寫了三個函數,實現該算法也需要更多的編程努力,但實際上程序代碼量的多少與程序的效率根本并沒有什么必然的聯系。

該算法的時間復雜度為時間復雜度O(N·logN),效率明顯高于前兩種

四、一層循環——累計遍歷法

(時間復雜度O(N))

這種方法,將循環減為一層,每次累加,并判斷當前最大值(thisSum)與標準最大值(maxSum)的關系。

雖然整體只進行了一趟循環,但是便于理解,在這里分成了6部分,每次更新thisSum的值并與maxSum比較。

public static int maxSubSum4(int[] arr){int maxSum = 0;int thisSum = 0;for(int j = 0;j<arr.length;j++){thisSum += arr[j];if(thisSum > maxSum){maxSum = thisSum;}else if(thisSum < 0){thisSum = 0;}}return maxSum;}

這種算法的效率是非常明顯的,時間復雜度為O(N),這種方法可以算是近乎完美的一種求解最大子列和的算法。根據總結:任何負的子序列都不可能是最大子序列的前綴,所以可以知道,只要是首位元素為負數的肯定不是最大子列的組成部分。即如果某個子列的首位為負數,那么它一定要借助后面的非負數改進。
而且這種算法還有一種優點就是,它只對數據掃描一次,在任何時刻,算法都可以對它已經讀入的數據給出正確的答案(具備這種特性的算法叫做聯機算法)


下面是四種算法的在不同N情況下的時間復雜度情況:

通過觀察我們可以發現,在小量輸入的情況下,幾種算法的復雜度基本上都是眨眼之間能夠完成的。但是在大量數據的情況下,我們可以看出,后兩中算法仍然是能夠在短時間內高效的完成同一件事,而前兩種卻顯得異常乏力。



題外話:之前在暑假期間,利用C語言,完成了基本的數據結構算法博客的書寫,雖然短時間內能夠記住相關的算法,但是幾個月來不經常接觸,導致水平仍是停滯不前。鑒于現正在自學java,所以我將通過java來繼續學習數據結構與算法這方面的知識。一方面可以通過撰文的形式加深記憶,另一方面,由于下學期學校會組織參加ACM大賽、數學建模大賽等比賽,一定要抽出足夠的時間來學習算法。

才疏學淺,尚有諸多不懂之處,文章多有疏漏,還望前輩斧正。

本系列專欄所有的算法均參考Mark Allen Weiss先生的《數據結構與算法分析–Java語言描述》第三版。

總結

以上是生活随笔為你收集整理的最大子列和问题(JAVA)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。