数组精选题目三连(5)
子數(shù)組的最大累加和問(wèn)題
輸入一個(gè)整形數(shù)組,求數(shù)組中連續(xù)的子數(shù)組使其和最大。比如,數(shù)組x
應(yīng)該返回 x[2..6]的和187.
?
這四個(gè)代碼完成的功能都是求最大子數(shù)組(注意用詞準(zhǔn)確,子數(shù)組連續(xù),子序列可以不連續(xù))。
1)
for(i = 1; i <= n; i++)scanf("%d", &num[i]); ans = num[1]; for(i = 1; i <= n; i++) {for(j = i; j <= n; j++) {s = 0;for(k = i; k <= j; k++)s += num[k];if(s > ans)ans = s;} }分別枚舉每一個(gè)子數(shù)組的起點(diǎn)和終點(diǎn),也就是i和j,對(duì)于每一個(gè)起點(diǎn)和終點(diǎn),對(duì)中間部分求和,也就是k循環(huán)。顯然有n個(gè)起點(diǎn)n個(gè)終點(diǎn)(去重減半,不影響復(fù)雜度),所以子數(shù)組數(shù)量為O(N^2),對(duì)于每個(gè)子數(shù)組,我們要遍歷一下求和,子數(shù)組長(zhǎng)度1-n不等,遍歷一遍平均O(N),乘起來(lái)O(N^3).(注意可能產(chǎn)生時(shí)間更大的錯(cuò)覺(jué))。找出所有子數(shù)組中最大的即可。
2)
for(i = 1; i <= n; i++)scanf("%d", &num[i]); sum[0] = 0; for(i = 1; i <= n; i++) {sum[i] = num[i] + sum[i - 1]; } ans = num[1]; for(i = 1; i <= n; i++) {for(j = i; j <= n; j++) {s = sum[j] - sum[i - 1];if(s > ans) ans = s;} }預(yù)處理出每一個(gè)以第一個(gè)元素開(kāi)始,第i個(gè)元素結(jié)尾的子數(shù)組和,還是枚舉每個(gè)起點(diǎn)終點(diǎn),但是我們求和時(shí)直接減就可以了,不用遍歷。對(duì)于每個(gè)子數(shù)組,操作為O(1),子數(shù)組數(shù)量O(N^2),所以總時(shí)間O(N^2).
3)
int solve(int left, int right) {if(left == right)return num[left];mid = (left + right) / 2;lans = solve(left, mid);rans = solve(mid + 1, right);sum = 0, lmax = num[mid], rmax = num[mid + 1];for(i = mid; i >= left; i--) {sum += num[i];if(sum > lmax) lmax = sum;}sum = 0;for(i = mid + 1; i <= right; i++) {sum += num[i];if(sum > rmax) rmax = sum;}ans = lmax + rmax;if(lans > ans) ans = lans;if(rans > ans) ans = rans;return ans; }int main(void) {scanf("%d", &n);for(i = 1; i <= n; i++)scanf("%d", &num[i]);printf("%d\n", solve(1, n));return 0; }二分,求左右兩邊最大子數(shù)組,取最大。但是還有一種情況:包含斷點(diǎn)的那些子數(shù)組也要考慮,請(qǐng)思考那兩個(gè)那兩個(gè)循環(huán)為什么那么寫(xiě)?最后邏輯為何正確?
4)動(dòng)態(tài)規(guī)劃入門(mén)思想
沒(méi)有枚舉,num[i]的含義是以下標(biāo)i結(jié)尾的所有子數(shù)組中最大的。
遍歷數(shù)組,對(duì)于第i個(gè)元素,它的所有子數(shù)組下標(biāo)范圍有[1,i],[2,i].....[i-1,i],還有它自己,我們看i-1個(gè)元素,他的子數(shù)組為[1,i-1],[2,i-1].....[i-1]。請(qǐng)想num[i]的含義,我們求i結(jié)尾的,只要把i-1結(jié)尾的最大加上i就好了,當(dāng)然如果i-1結(jié)尾最大子數(shù)組是負(fù)的,i結(jié)尾最大子數(shù)組就是它本身。
為什么O(N)?時(shí)間省在哪里了?我們省掉了許多沒(méi)必要的計(jì)算,計(jì)算i時(shí),之前的數(shù)組和已經(jīng)都計(jì)算過(guò),樸素算法并沒(méi)有記錄下來(lái),而是重復(fù)計(jì)算,造成時(shí)間浪費(fèi)。算法優(yōu)化的過(guò)程就是去掉重復(fù)計(jì)算的過(guò)程。
?
子矩陣的最大累加和問(wèn)題
給一個(gè)矩陣,請(qǐng)找出一個(gè)矩陣中,和最大的子矩陣。
?
?
?
如果大家看懂了之前的講解,我給個(gè)提示:利用第二個(gè)代碼和第四個(gè)代碼思想的結(jié)合
?
?
解釋:
1???2??3???4
-1 -2??1???2
1???3???-2??1
-1??-2??-1??-3
如圖是前三行整體最大
怎么做呢?
先用第二個(gè)代碼的思想,我們進(jìn)行預(yù)處理
每個(gè)數(shù)代表這一列到這個(gè)數(shù)位置截止,累加和。
1??2??3??4
0??0??4??6
1??3??2??7
0??1??1??4
然后,我們枚舉每一列的起點(diǎn)和終點(diǎn)分別為第0,1,2,3行
然后壓縮成一維來(lái)做
比如求1-3行的這個(gè)矩形,我們拿0和3行減一下就行了
0-1,1-2,1-3,4-4=-1,-1,-2,0就是1-3行壓縮后的結(jié)果
然后按一維dp來(lái)做就好
?
子數(shù)組的最大累乘積
題目:
給定一個(gè)double類(lèi)型的數(shù)組arr,其中的元素可正、可負(fù)、可為0。返回子數(shù)組累乘的最大乘積。
思路:
假設(shè)以arr[i-1]結(jié)尾的數(shù)組最小累乘積為min,最大累乘積為max,那么以arr[i]結(jié)尾的數(shù)組的最大累乘積可能有三種情況。
- max*arr[i]//本身乘之前的最大累乘
- min*arr[i]//可能是負(fù)負(fù)得正變成最大的
- arr[i]//可能就是它本身,比如之前的max小于1
?
總結(jié)
以上是生活随笔為你收集整理的数组精选题目三连(5)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: leetcode172. 阶乘后的零 最
- 下一篇: 18暑期培训总结