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 最大子矩陣和 求最大子矩陣的和,...