之前我們說了遞迴的重點就是乙個終止條件(也叫邊界條件);此處的邊界條件就是f(n)中的n=1;當n=1時就表示遞迴進入了最低成,下一步就是要往上返回了。
# 算 n 的階乘(假設n不為0)
deff
(n):
if n==1:
return
1else
:return n*f(n-1)
print
(f(6))
#720
再來說這段簡單的**,由兩部分組成。乙個是終止條件n==1;當往深了走走到n=1了,開始往外返回計算的結果了;第二部分是 呼叫函式本身的部分了,就是處理問題的邏輯的方式了,階乘,大家都知道一路乘下去直到1。一般的遞迴最難的部分就是這個邏輯的編寫了,相當於什麼呢?相當於,你要找到乙個通用的辦法,來結合乙個數量級很大的運算;得多見識一些遞迴才好提高;
想想思路;斐波那契數是前面連續兩項相加得來的。那麼遞迴邏輯部分就可以大致寫成f(n) = f(n-2)+f(n-1);這個就是核心**,是不是看起來很簡單,那麼還差乙個終止條件是不是?觀察斐波那契數列的前幾個資料 f(1)=1 f(2)=1 f(3)=2前兩項是固定的都是1,那麼簡單了,遞迴的終止條件就是往前推到第2項或者第1項的時候就返回1,即,終止條件是:n<=2時返回第一或者第二項的值1;
def
f(n)
:if n<=2:
return
1else
:return f(n-2)
+f(n-1)
print
(f(20))
# 6765
def divide_conquer
(problem, paraml, param2,..
.): # 往裡走的終止條件
if problem is none:
print_result
return
# 準備資料
data=
prepare_data
(problem)
# 將大問題拆分為小問題
subproblems=
split_problem
(problem, data)
# 處理小問題,得到子結果
subresult1=self.
divide_conquer
(subproblems[0]
,p1,
..…)
subresult2=self.
divide_conquer
(subproblems[1]
,p1,..
.)subresult3=self.
divide_conquer
(subproblems[2]
,p1,
.…) # 對子結果進行合併 得到最終結果
result=
process_result
(subresult1, subresult2, subresult3,..
.)
在不用遞迴思路的情況下,我們第一思路就是做乙個n次的迴圈,每次迴圈都x乘上一次被複製的結果;用分治思想來處理(從中間拆分成兩部分:偶數次冪對半分,奇數次冪單獨乘乙個x後再分(n-1)/ 2 ):
1,終止條件:思路是n次方分成兩個[n/2]次方相乘,最後n=0了表示不在拆分了;
2,準備資料,處理小問題:技術次冪先乘x再二分遞迴。偶數次冪直接二分遞迴;
def
f(x, n)
:# 【確定不斷切分的終止條件】
if n ==0:
return
1# 【準備資料,並將大問題拆分為小的問題】
# 奇數次冪先乘x,後剩下偶數次冪再對半遞迴
if n %2==
1:# 【處理小問題,得到子結果】
p = x * f(x, n -1)
return p
return f(x * x, n /2)
print
(f(3,5
))# 243
首先來說說快排的思路:每次都選擇乙個標誌位,比標誌小的放左邊,比標誌大的放右邊。至於這個標誌呢,就選定每邊的第乙個數字。好,選擇思路有了,怎麼實現,如果不考慮空間複雜度,我們的實現方式是新增新陣列,每次拆分排序後,生成兩個臨時陣列(乙個放小於標誌位的數,乙個放大於標識位的數),下一層遞迴再生成兩個新陣列,這個實現起來豈不是增加極大的記憶體浪費麼?有沒有辦法再不增加空間的情況下實現呢
在原先的陣列的結構彙總進行移動數字。如何實現呢?通過用乙個變數臨時存放標識位,那麼,標識為所在的陣列中的位置不久空出來了麼?只要陣列中有空位,便可實現數字交換了呀;具體實現是:首位交替掃瞄
什麼是首尾交替掃瞄呢?引用指標概念,left,right指標最開始分別指向陣列的首尾,取第乙個數字為標誌位,那就是nums[left];那麼left指向的位置空出來了,此時拿rigt位置的數跟標誌位比較,小,就把right位置的數放到left的位置上,left++(left原來的數字已經被存到標識位變數pivot中了),若比標誌位大,直接用right–比較(為什麼呢?因為大的在右邊啊,都最後乙個了還不夠右嗎?)。交換後,right位置是不是空的呀?這個時候就比較left的位置啦(為啥是從left++開始,left被right覆蓋後,left得++指向左數第二個元素了),繼續重複上面步驟。**如下:
# --
----
----
----
----
----
----
-快速排序--
----
-------
def quick_sort
(nums: list, left:
int, right:
int)
-> none:
#1,終止條件
if left < right:
i = left
j = right
# 取第乙個元素為標誌
pivot = nums[left]
while i != j:
# 交替掃瞄和交換
# 從右往左找到第乙個比標誌位小的元素,交換位置
while j > i and nums[j]
> pivot:
j -=
1if j > i:
# 如果找到了,進行元素交換
nums[i]
= nums[j]
i +=
1 # 從左往右找到第乙個比標誌位大的元素,交換位置
while i < j and nums[i]
< pivot:
i +=
1if i < j:
nums[j]
= nums[i]
j -=
1 # 至此完成一趟快速排序,標誌位的位置已經確定好了,就在i位置上(i和j)值相等
nums[i]
= pivot
# 以i為標誌進行子串行元素交換
quick_sort
(nums, left, i-1)
quick_sort
(nums, i+
1, right)
# 測試**
import random
data =
[random.
randint(-
100,
100)
for _ in range(10
)]print
(data)
quick_sort
(data,0,
len(data)-1
)print
(data)
# [23,-
77,5,
26,-67
,-41,
-19,-
89,84,
-56]# [-89
,-77,
-67,-
56,-41
,-19,
5,23,
26,84]
Leetcode 分治演算法
題目描述 在未排序的陣列中找到第 k 個最大的元素。請注意,你需要找的是陣列排序後的第 k 個最大的元素,而不是第 k 個不同的元素。示例 1 輸入 3,2,1,5,6,4 和 k 2 輸出 5 解法 堆 思路 建立乙個大頂堆,並保持堆的大小小於等於k。堆內的排序從堆頂遞增,最後的堆頂就是所求。時間...
分治演算法的學習筆記
分治演算法應用一 漢諾塔問題 問題描述 漢諾塔問題 於乙個古老的傳說,世界剛被建立的時候,有一座鑽石寶塔,上面有64個金碟,所有碟子按照從大到小的順序從塔底堆到塔頂,從世界創世開始,牧師們一直在努力將塔a的碟子借助b移到c上,每次只能移動乙個,而且不能讓小的放在大的下面 原理 對漢諾塔問題的求解簡化...
組隊學習 分治演算法 打卡
將原本複雜的問題,拆分成相同解決方法的簡單的小問題,然後將小問題的答案歸併成初始問題的解。採用遞迴的方式,將問題層層分解,直到子問題滿足設定好的終止條件結束遞迴求解子問題的解,然後將解歸併。示意圖如下 示例1 輸入 3,2,3 輸出 3 示例2 輸入 2,2,1,1,1,2,2 輸出 2 首先想到的...