数据结构作业1 讲解和拓展
原題來自雪梨教育
http://www.edu2act.net/task/list/checked/
題后給出講解和擴(kuò)展
任務(wù)1_1 比較下列算法的時(shí)間復(fù)雜度
任務(wù)描述:
? ? 下面給出4個(gè)算法,請(qǐng)分析下列各算法的時(shí)間復(fù)雜度,請(qǐng)寫清楚題號(hào),并將每個(gè)小題的分析過程寫出來,并給出分析結(jié)果。
(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;} }(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;} }(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; }(4)
for(i = 1; i <= n; i++)scanf("%d", &num[i]);num[0] = 0; ans = num[1]; for(i = 1; i <= n; i++) {if(num[i - 1] > 0) num[i] += num[i - 1];elsenum[i] += 0;if(num[i] > ans) ans = num[i]; }任務(wù)1_2 數(shù)字反轉(zhuǎn)的時(shí)空復(fù)雜度
任務(wù)描述:
下面兩個(gè)函數(shù)fun1和fun2都是實(shí)現(xiàn)對(duì)整數(shù)的逆序輸出功能,請(qǐng)根據(jù)下面題目要求,給出答案。
(1) 請(qǐng)分析函數(shù)fun1的時(shí)間復(fù)雜度和空間復(fù)雜度;
(2) 請(qǐng)分析函數(shù)fun2的時(shí)間復(fù)雜度和空間復(fù)雜度。
代碼如下:
?
int fun1(int n) {int rev = 0;while (n != 0) {int pop = n % 10;n /= 10;rev = rev * 10 + pop;}return rev; }void fun2(int n) {printf("%d", n % 10);if(n / 10 != 0)fun2(n / 10); }int main(void) {printf("%d\n", fun1(10203)); fun2(10203);return 0; }?
講解:
說頻度,或者求和公式往上堆出來的解釋,?都是耍流氓
沒有專業(yè)名詞的講解才是講解
?
直接粘貼我交的作業(yè)
?
先用數(shù)學(xué)說明,后解釋題意并分析。
分別為O(N^3),O(N^2),O(N*logN),O(N).
數(shù)學(xué):
1)第一個(gè)循環(huán)O(N)
對(duì)于每一個(gè)i來說,j執(zhí)行n-i+1次,對(duì)于每個(gè)j來說,k執(zhí)行j-i+1次,我們把常數(shù)去掉,
對(duì)于每一個(gè)i,執(zhí)行的常數(shù)操作為1+2+3+...+(n-i+1),等差數(shù)列[1+(n-i+1)](n-i+1)/2約等于(n-i)^2而i=1,2,....n,分別執(zhí)行常熟操作次數(shù)為(n-1)^2,(n-2)^2......1^2,0^2.,可以看出是平方函數(shù)求和,而對(duì)x^2求和n項(xiàng)的公式為(n^3)/3+(n^2)/2+n/6,我們只看最大,去掉常數(shù),也就是O(N^3).
O(N^3)+O(N)當(dāng)然還是O(N^3)
2)前兩個(gè)循環(huán)都是O(N),下面兩重循環(huán),對(duì)于每個(gè)i,j執(zhí)行n-i次,當(dāng)i=1,2....n,j執(zhí)行次數(shù)為n-1,n-2....1,0,可以看出是等差數(shù)列求和,最高項(xiàng)是(n^2)/2,去掉系數(shù),時(shí)間復(fù)雜度為O(N^2).
加起來:O(N^2)+O(N)+O(N)=O(N^2)
3)分析solve函數(shù):采用二分,將序列分成兩份,直到不可再分,執(zhí)行的兩個(gè)循環(huán)加起來就是遍歷一遍左右端點(diǎn)之間數(shù)的復(fù)雜度。我們看所有從長(zhǎng)度為1的子數(shù)組,數(shù)量為n,合并后,所有長(zhǎng)度為2的子數(shù)組,數(shù)量為n/2,再合并,長(zhǎng)度為4的子數(shù)組,數(shù)量為n/4,我們會(huì)發(fā)現(xiàn)對(duì)于每個(gè)長(zhǎng)度1,2^2,2^4,2^3,的子數(shù)組,遍歷一遍所有長(zhǎng)度一樣的子數(shù)組的復(fù)雜度都是O(N),設(shè)一共有x種長(zhǎng)度,2^x=n,很明顯x=log(2,n)。
每次O(N),次數(shù)o(log(2,n)),乘起來O(n*logn)
看main函數(shù),接收數(shù)據(jù)是O(N),加solve,等于O(n*logn)
4)接收數(shù)據(jù)O(N),一個(gè)循環(huán)O(N),加起來O(N)。
?
下面我根據(jù)完成的功能和思路分析一下:(思路簡(jiǎn)單,文字略長(zhǎng),不太會(huì)敘述)
這四個(gè)代碼完成的功能都是求最大子數(shù)組(注意用詞準(zhǔn)確,子數(shù)組連續(xù),子序列可以不連續(xù))。
1)分別枚舉每一個(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),乘起來O(N^3).(注意可能產(chǎn)生時(shí)間更大的錯(cuò)覺)。找出所有子數(shù)組中最大的即可。
2)預(yù)處理出每一個(gè)以第一個(gè)元素開始,第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)二分,求左右兩邊最大子數(shù)組,取最大。但是還有一種情況:包含斷點(diǎn)的那些子數(shù)組也要考慮,請(qǐng)思考那兩個(gè)那兩個(gè)循環(huán)為什么那么寫?最后邏輯為何正確?
4)動(dòng)態(tài)規(guī)劃入門思想
沒有枚舉,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í)間省在哪里了?我們省掉了許多沒必要的計(jì)算,計(jì)算i時(shí),之前的數(shù)組和已經(jīng)都計(jì)算過,樸素算法并沒有記錄下來,而是重復(fù)計(jì)算,造成時(shí)間浪費(fèi)。算法優(yōu)化的過程就是去掉重復(fù)計(jì)算的過程。
?
1-2
fun1:時(shí)間O(log10,N),空間O(1)
FUN2:時(shí)間O(log10,N),空間O(log10,N)
第一個(gè)函數(shù)只是有限幾個(gè)變量,所以空間O(1),一個(gè)循環(huán)n每次縮小十倍,時(shí)間O(log10,N).
第二個(gè)函數(shù)遞歸調(diào)用,這個(gè)函數(shù)沒執(zhí)行完就跳到另外的函數(shù),會(huì)壓函數(shù)棧,空間O(log(10,n)),
而時(shí)間還是O(log10,N),復(fù)雜度沒變但是時(shí)間稍長(zhǎng)。
?
?
?
作業(yè)完了
?
我們說拓展:如何求二維數(shù)組的最大和子數(shù)組?
如果大家看懂了之前的講解,我給個(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行
然后壓縮成一維來做
比如求1-3行的這個(gè)矩形,我們拿0和3行減一下就行了
0-1,1-2,1-3,4-4=-1,-1,-2,0就是1-3行壓縮后的結(jié)果
然后按一維do來做就好
時(shí)間復(fù)雜度:n行m列:
預(yù)處理:每個(gè)元素弄一遍,O(N*M)
枚舉壓縮:起點(diǎn)n個(gè)終點(diǎn)n個(gè),數(shù)量:O(N^2),對(duì)于每個(gè)矩陣,我們壓縮為一維,只要減一下就好,O(M)
dp:每個(gè)一維O(M)
?
求最大子長(zhǎng)方體或者多維也一樣,預(yù)處理,三維壓二維,二維壓一維,按一維dp來做。
?
算法優(yōu)化的過程就是去除重復(fù)計(jì)算過程的過程
想象一下沒有預(yù)處理沒有dp的樸素做法時(shí)間是多少?
算法的魅力
?
以前寫過這個(gè)問題的總結(jié)了,所以這次可能寫的有點(diǎn)簡(jiǎn)單。看不懂再去之前博客找找
總結(jié)
以上是生活随笔為你收集整理的数据结构作业1 讲解和拓展的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构课上笔记9
- 下一篇: leetcode461. 汉明距离