演算法與資料結構 4 6 最大子段和 貪心優化

2022-03-01 18:41:42 字數 4657 閱讀 9020

1、時間方面優化:迴圈可以合併(迴圈方向一致,迴圈最大值也是,並且兩個迴圈之間沒有什麼邏輯操作**)

2、空間方面優化:**中只用到了a[i],所以a陣列可以用乙個變數來代替

#include #include 

using

namespace

std;

intmain()

cout

return0;

}

最大子段和(最大連續子串行的和)

題目描述

給出乙個長度為 n 的序列 a,選出其中連續且非空的一段使得這段和最大。

輸入格式

第一行是乙個整數,表示序列的長度 n。

第二行有 n 個整數,第 i 個整數表示序列的第 i 個數字 ai

輸出格式

輸出一行乙個整數表示答案。

輸入輸出樣例輸入7

2 -4 3 -1 2 -4 3輸出4

說明/提示

樣例解釋

選取 [3,5] 子段最大,其和為 4。

資料規模與約定

對於40%的資料,保證n<=2×10^3

對於100%的資料,保證1<=n<=2×10^5, -10^4<=a[i]<=10^4

題目提交位置:

p1115 最大子段和 - 洛谷

1 /*

2 列舉法

3 4 分析:

5 我們可以直接按照題目的要求來列舉就好了

6 7 題目的要求是要 求a[1]-a[n]中連續非空的一段的和最大

8 那麼我們把每個連續的一段都列舉出來,然後來算出裡面的和,找出最大值即可

9 10 所以在這個需求下:

11 我們需要列舉每一段的起點、每一段的終點

12 然後對這一段進行求和

13 14 列舉變數:每一段的起點、終點

15 列舉範圍:起點:1-n,終點:起點-n

16 列舉判斷條件:

17 求和得到每一段的和,在這些和裡面選出最大的

18 19 時間複雜度:

20 o(n^3)

21 22 演算法思路:

23 1、列舉每一段的起點和終點

24 2、對每一段進行求和,在這些和裡面選出最大的

25 26 */

27 #include 28 using namespacestd;

29 int a[200005];

30 intmain()

37 //1、列舉每一段的起點和終點

2 列舉優化

3 4 可以把求和的那層迴圈去掉,我們可以對資料做預處理

5 用s[i]表示第乙個數到第i個數這個序列的和

6 7 那麼求s[i-j](第i個數到第j個數這個序列的和)的時候,

8 可以直接用s[j]-s[i]+a[i]即可

9 s[j]-s[i]表示的是i+1到j這個序列的和,所以需要加上a[i]

10 11 現在的時間複雜度:

12 o(n)+o(n^2)=o(n^2)

13 14 優化方法:

15 減少重複計算

16 17

18 */

19 #include 20 using namespacestd;

21 int a[200005];

22 int s[200005]=;

23 intmain()

31 //1、列舉每一段的起點和終點

2 3 樣例

4 75 2 -4 3 -1 2 -4 3

6 7 分治解法

8 假定a[1]-a[n]的序列對應的區間[l...r],其中間位置為mid,其最大和的子串行為[i...j]。

9 那麼顯然,最大連續子串行的位置只有三種可能:

10 ①完全處於序列的左半:l<=i<=j<=mid

11 ②跨越序列中間:i<=mid<=j<=r

12 ③完全處於序列的右半:mid13

14 15 只需要分別求出三種情況下的值,取他們最大的即可。

16 其中,很容易求出第二種情況,第二種情況也就是包含mid的子串行,

17 也就是[i...mid...j],而求[i...mid...j]的最大值,

18 即求出區間[i..mid]的最大值maxx1與區間[mid..j]的最大值maxx2,將其合併即可。

19 合併之後就變成了[i...mid mid...j],mid出現了兩次,要減掉一次

20 所以[i...mid...j]的最大值就是maxx1+maxx2-mid

21 22 複雜度o(n)

23 如何處理第一種和第三種情況呢?

24 也不難發現,

25 第一種情況,其實就是求區間[l..mid]中的最大值,

26 第三種情況就是求區間[mid+1..r]中的最大值。那麼,只需遞迴求出即可。

27 顯然,該解法的複雜度為o(nlogn)通過此題是沒問題的。

28 29

30 演算法時間複雜度

31 o(nlogn):二分是logn,處理第二種情況是n,所以合起來就是o(nlogn)

32 33

34 如何求區間[i..mid]的最大值與區間[mid..j]的最大值,

35 換句話說,也就是如何求以mid為尾的子串行的最大值 和 以mid為頭的子串行的最大值

36 先說以mid為頭的子串行的最大和

37 也就是[mid],[mid...mid+1],[mid...mid+2]......[mid...mid+j]這些序列裡面的最大值

38 int maxx2=-0x7fffffff;

39 int sum2=0;

40 for(int k=mid;k<=j;k++)

44 45 求以mid為尾的子串行的最大和

46 int maxx1=-0x7fffffff;

47 int sum1=0;

48 for(int k=mid;k>=i;k--)

52 53 maxx1+maxx2-a[mid]

54 55

56 遞迴做分治:

57 a、遞迴的終止條件:

58 因為我們的遞迴是為了求l到r序列的子串行的最大值,

59 所以當區間只有乙個元素時,就是終止條件,那個元素就是子串行的最大值

60 b、遞迴的遞推表示式:比較方式1、2、3的最大值。第2種跨越mid值的需要我們去計算,1,3種情況又轉化成了子問題

61 c、遞迴的返回值:子串行的最大和

62 63

64 演算法步驟:

65 1、計算第二種跨越mid情況的序列的最大和

66 2、比較方式1、2、3的最大值

67 68

69 70 樣例:

71 4

72 -1 3 -1 -2

73 結果是3

74 75 mid=(1+4)/2 2

76 ①完全處於序列的左半:l...mid:-1 3 對應的是3

77 ②跨越序列中間:3+3-3=3

78 ③完全處於序列的右半:mid+1...r:-1 -2 對應的結果是-1

79 80 -1 3

81 mid=1

82 ①完全處於序列的左半:l...mid:-1

83 ②跨越序列中間:-1+2-(-1)=2

84 ③完全處於序列的右半:mid+1...r:3

85 86 */

87 #include 88 #include 89 using namespacestd;

90 int a[200005];

91 //分治(二分)求最大連續子串行的和

92 int find(int l,intr)

103

104 //b、求以mid為頭的子串行的最大和

105 int maxx2=-0x7fffffff;

106 int sum2=0;

107 for(int k=mid;k<=r;k++)

111

112 //2、比較方式1、2、3的最大值

113 return max(max(find(l,mid),find(mid+1,r)),maxx1+maxx2-a[mid]);

114 }

115

116 intmain(){

117 intn;

118 cin>>n;

119 for(

資料結構與演算法 最大子序和

在這裡插入描述 動態規劃 設定乙個陣列adds儲存以所給陣列中以每個資料為結尾的最大陣列序的和,具體找法是,從左向右開始,若前半部分資料和大於0,則加上,若小於則捨去,最後在迴圈在adds中的最大值。int len nums.size int adds len adds 0 nums 0 for i...

資料結構與演算法 最大子列和問題

問題 給定n個整數序列,求該序列中存在的最大的連續n個整數和。分析 方法1 最自然的方法是設定子列和的左端索引i和右端索引j,然後通過遍歷的方法找出最大的子列和,其中最簡單的陣列求和也是遍歷相加,因此將會有三層迴圈,計算複雜度為o n 3 為 int maxsum1 int a,int n int ...

最大子段和與最大子矩陣和

最大子段和。求一段連續的子段裡面最大的值。1 include2 const int maxn 10006 3 inta maxn 45 intmain 614 15for int i 1 i n i 20 printf d n ans 21 22return0 23 最大子矩陣和 求最大子矩陣的和,...