1. 遞迴本質
遞迴很常見應用很廣,常常看到的遞迴**非常簡潔,但是實現強大。
遞迴的表現形式是函式自己呼叫自己,有點繞,所以接下用例子講述下計算機怎麼實現遞迴的。
最簡單的例子,求乙個陣列的最大值。這個基本方法是不用遞迴的,可以遍歷一遍,但是強制用遞迴實現。
思路:把陣列切一半,左半部分求最大值,右半部分求最大值,之後取兩者中的最大值,左右部分遞迴下去。
c++ 簡單實現
int getmax(vector& arr, int left, int right)
這樣乙個遞迴函式,系統怎麼實現的?
函式在系統裡怎麼實現的,用棧,函式結束就會清空棧裡儲存的臨時變數。
例如 arr= [1 , 3, 2, 4] 呼叫getmax(arr, 0, 3),系統會開闢乙個棧,存入 如圖1.1,現在執行在第1行,left=0,right=3,mid未定義以及其他資訊,接下去執行到第6行呼叫getmax(arr,0,1), 存入棧如圖1.2,執行到第6行,left=0,right=3,mid=1。同樣進入getmax(arr,0,1)函式left(0)不等於right(1),mid=0,執行到第6行getmax(arr,0,0),存入棧如圖1.3。接下來left等於right,返回arr[0]=1賦給leftmax,彈出棧上的(6,0,1,0…),把變數資訊取出此時left=0,right=1,mid=0,leftmax=1, 執行到第7行getmax(arr,1,1),又壓入棧如圖1.4, 返回rightmax=arr[1]=3, 彈出最上一行,返回rightmax(1)rightmax(3)中大的3賦給leftmax,此時彈出棧中倒數第二行,此時棧中剩下如圖1.5,如此下去…
這樣應該已經很清楚了,所以遞迴就是系統幫你壓棧而已。
所以遞迴函式都可以轉化為非遞迴?當然,只要自己來壓棧就可以實現。
為什麼要把遞迴轉化為非遞迴,因為遞迴函式系統壓棧會有棧溢位的可能,如果遞迴非常深的話。
遞迴最重要的就是理解分治思想。
2. 估算遞迴時間複雜度
如果乙個遞迴問題可以轉化為:
t (n
)=at
(n/b
)+o(
nd)t(n) = at(n/b) + o(n^)
t(n)=a
t(n/
b)+o
(nd)
n: 父問題樣本量,n/b:子問題樣本量,a:發生次數,o(n
d)o(n^)
o(nd
):除了遞迴以外的時間複雜度
如果乙個遞迴問題可以轉化成如上公式,那麼他的時間複雜度可以通過master公式給出
上面這個求陣列最大值的例子,其t(n
)=2t
(n/2
)+o(
1)t(n) = 2t(n/2) + o(1)
t(n)=2
t(n/
2)+o
(1) a=2,b=2,d=0,滿足log(2,2) > 0, 複雜度為o(n)
master公式不適用的情況:子問題的規模不一樣 ,如 t(n
)=t(
n/5)
+t(n
/3)+
o(1)
t(n) = t(n/5) + t(n/3) + o(1)
t(n)=t
(n/5
)+t(
n/3)
+o(1
)3. 歸併排序
思路:把左半部分排好序,把右半部分排好序,準備乙個陣列,類似外排的方式依次填入這個陣列,如果某部分填完了,把另一部分拷貝進去。
這樣可以直接寫出,左右規模n/2,t(n
)=2t
(n/2
)+o(
n)t(n) = 2t(n/2) + o(n)
t(n)=2
t(n/
2)+o
(n),套用master公式,複雜度o(nlogn)
c++ 實現
void merge(vector& arr, int left, int mid, int right)
while (start1 <= mid)
while (start2 <= right)
for (unsigned int i = 0; i < help.size(); ++i) }
void sortprocess(vector& arr, int left, int right)
// 主函式
void mergesort(vector& arr)
額外空間複雜度是o(n),為什麼?只要申請乙個n大小的陣列,每次排left到right,就取[left, right]。
4. 小和問題
其實只是在歸併排序**基礎上略微修改,核心**就這一句
result += arr[start1] < arr[start2] ? (right - start2 + 1) * arr[start1] : 0;
外排合併的時候,右邊比它大的話,小和就是從這個右邊數起右邊總共的個數*當前數
這裡有句** int mid = left + ((right - left) >> 1); 看著很怪,其實等同於int mid = (left + right) / 2,這樣就清楚了。
因為 left + right 有可能會溢位,所以轉化為 mid = left + (right - left) / 2 不會溢位 ,>> 右移等同於 /2,同樣是o(1)複雜度,不過位運算比算術執行快
牛客網 壓縮演算法
小q想要給他的朋友傳送乙個神秘字串,但是他發現字串的過於長了,於是小q發明了一種壓縮演算法對字串中重複的部分進行了壓縮,對於字串中連續的m個相同字串s將會壓縮為 m s m為乙個整數且1 m 100 例如字串abcabcabc將會被壓縮為 3 abc 現在小q的同學收到了小q傳送過來的字串,你能幫助...
牛客網 劍指offer 遞迴 (1)
出現的問題 原因 返回值沒有考慮到所有情況 輸入引數n是乙個整數,自己只考慮n 0,n 1,n 2,n 39的情況,一直報錯。改正方案 加上else,判斷其他情況均輸出0,編譯通過 菲波那切數列數列有很多變形的問題 問題1 兔子問題 題目描述 已知一對兔子每乙個月可以生一對小兔子,而一對兔子出生後....
牛客網 汽水瓶 遞迴方法
題目描述 有這樣一道智力題 某商店規定 三個空汽水瓶可以換一瓶汽水。小張手上有十個空汽水瓶,她最多可以換多少瓶汽水喝?答案是5瓶,方法如下 先用9個空瓶子換3瓶汽水,喝掉3瓶滿的,喝完以後4個空瓶子,用3個再換一瓶,喝掉這瓶滿的,這時候剩2個空瓶子。然後你讓老闆先借給你一瓶汽水,喝掉這瓶滿的,喝完以...