1. 遞迴與分治
阿新 • • 發佈:2019-06-08
遞迴
在函式內部,可以呼叫其他函式。如果一個函式在內部呼叫自身本身,這個函式就是遞迴函式。
n-皇后
在n×n格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。
解析:定義一個長度為N的陣列,陣列的每一項值表示皇后所在的的行數,具體演算法解釋如(八皇后為例)。
class Recursion: ''' 遞迴 ''' def __init__(self): pass ''' name: n皇后演算法 desc:在n×n格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。 ''' def n_queens(self, A, cur=0): ''' :param A: 長度為n的陣列,存放每一列皇后所在的行數 :param cur: 當前擺放的位置 :return: none ''' if cur == len(A): # 擺放完所有位置,queen陣列記錄八個皇后各自的列數 print(A) return 0 for col in range(len(A)): # 初始賦值 A[cur], flag = col, True for row in range(cur): # 當前點不在前一個點的同一行,也不在同一斜線 # abs(col - A[row]) == cur - row可以理解成點斜式:y-y0=k(x-x0),其中k=1 # => y-x = y0-x0 即等式成立,那麼(y0,x0)在直線上 # 加絕對值是因為可能正斜線與反斜線,斜率大小相等 if A[row] == col or abs(col - A[row]) == cur - row: flag = False break if flag: # 遞迴 self.n_queens(A, cur + 1) eight_queens = Recursion() eight_queens.n_queens([None]*8)
總結:遞迴運算主要注意兩個條件,一個是初始狀態,二是變化量,其中變化量一定是能確保函式結束的。
分治
分治法的設計思想是:將一個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。
分治策略是:對於一個規模為n的問題,若該問題可以容易地解決(比如說規模n較小)則直接解決,否則將其分解為k個規模較小的子問題,這些子問題互相獨立且與原問題形式相同,遞迴地解這些子問題,然後將各子問題的解合併得到原問題的解。這種演算法設計策略叫做分治法。
二分搜尋
二分搜尋法,它充分利用了元素間的次序關係,採用分治策略,可在最壞的情況下用O(log n)完成搜尋任務。它的基本思想是,將n個元素分成個數大致相同的兩半,取a[n/2]與欲查詢的x作比較,如果x=a[n/2]則找到x,演算法運算終止。
class DivideAndConquer: ''' 分治 ''' def __init__(self): pass ''' name: 二分搜尋演算法 desc: 將n個元素分成個數大致相同的兩半,取a[n/2]與欲查詢的x作比較,如果x=a[n/2]則找到x,演算法運算終止。 ''' def binary_search(self, li, elem): ''' :param li: 有序數列 :param elem: 待查詢元素 :return: 元素位置 ''' length = len(li) left = 0 right = length - 1 while left <= right: middle = int((left + right) / 2) if elem == li[middle]: return middle if elem > li[middle]: left = middle + 1 else: right = middle - 1 return None
歸併排序
歸併排序基於這樣一個技巧:將 2 個大小為 N/2 的已排序序列合併為一個 N 元素已排序序列僅需要 N 次操作。這個方法叫做歸併。(歸併排序詳解)
class DivideAndConquer:
'''
分治
'''
def __init__(self):
pass
'''
name: 歸併排序
desc: 其思想時將待排序的n個元素分成大小大致相同的兩個子集,分別對兩個子集進行排序,最終將排序好的子集合並
'''
def merge(self, letf, right):
# 合併ul[left]和ul[right]到merge
merge = []
while len(letf) > 0 and len(right) > 0:
if letf[0] <= right[0]:
merge.append(letf.pop(0))
else:
merge.append(right.pop(0))
if len(letf) <= 0:
merge.extend(right)
else:
merge.extend(letf)
return merge