牛客網演算法之遞迴

2021-09-24 05:47:34 字數 3647 閱讀 4162

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個空瓶子。然後你讓老闆先借給你一瓶汽水,喝掉這瓶滿的,喝完以...