第一條特徵:是絕大多數問題均可以知足的,由於問題的計算複雜性通常是隨着問題規模的增長而增長html
第二條特徵:是應用分治法的前提它也是大多數問題能夠知足的,此特徵反映了遞歸思想的應用數組
第三條特徵:是關鍵,可否利用分治法徹底取決於問題是否具備第三條特徵,若是具有了第一條和第二條特徵,而不具有第三條特徵,則能夠考慮用貪心法或動態規劃法app
第四條特徵:涉及到分治法的效率,若是各子問題是不獨立的則分治法要作許多沒必要要的工做,重複地解公共的子問題,此時雖然可用分治法,但通常用動態規劃法較好ide
求 ,base爲底數,a爲指數。spa
基本思想:對分治:code
def fast_power(base, a): # 指數爲0返回1 if a == 0: return 1.0 # 指數爲負數 elif a < 0: return 1 / fast_power(base, -a) # 指數爲奇數 elif a % 2: return fast_power(base * base, a // 2) * base # 指數爲偶數 else: return fast_power(base * base, a // 2) print(fast_power(2, 5)) # 32
列表沒有重複值,但可能存在多個峯值,返回任意一個峯值的index.
你能夠想象成 num[0] = num[n] = -∞, 第一位和最後一位爲負無窮
def search_peak(alist, start, end): if start == end: return start if start + 1 == end: if alist[start] > alist[end]: return start return end mid = start + (end - start) // 2 # 若是當前值大於前一個值,而且當前值大於後一個值,則當前值是峯值 if alist[mid - 1] < alist[mid] and alist[mid + 1] < alist[mid]: return mid # 若是前一個值大於當前值,而且當前值大於後一個值,呈降低趨勢,前方有峯值,不然後方有峯值 elif alist[mid - 1] > alist[mid] and alist[mid] > alist[mid + 1]: return search_peak(alist, start, mid-1) else: return search_peak(alist, mid + 1, end) alist = [1, 3, 5, 100, 63, 32, 60, 70, 23, 12, 2, 21, 32, 45, 39, 36,11] print(search_peak(alist, 0, len(alist) - 1)) # 7
給定兩個排好序的列表。這兩個數組只有一個不一樣的地方:
在第一個數組某個位置上多一個元素。請找到這個元素的索引位置。
def find_extra(lst1, lst2): index = len(lst2) left, right = 0, len(lst2) - 1 while left <= right: mid = left + (right - left) // 2 # 若是中間元素相同,則表示多餘元素在後面,不然在前面 if lst1[mid] == lst2[mid]: left = mid + 1 else: index = mid right = mid - 1 return index lst1 = [3, 5, 7, 9, 10, 11, 13] lst2 = [3, 5, 7, 9, 11, 13] print(find_extra(lst1, lst2)) # 4
在一個一維數組中找到連續的子序列,且這個子序列的加和值最大。
例如,一位數組序列爲 [−2, 1, −3, 4, −1, 2, 1, −5, 4]
則這個序列對應的加和值最大的子序列爲[4, −1, 2, 1], 其加和值爲6.
解決思路:
現將序列等分爲左右兩份,則最大子列只可能出如今三個地方:
import sys # O(nlogn) def sub_list(alist, left, right): if left == right: return alist[left] mid = left + (right - left) // 2 # 左邊序列的最大和 left_sub = sub_list(alist, left, mid) # 右邊序列的最大和 right_sub = sub_list(alist, mid + 1, right) # 中間序列的最大和 mid_sub = max_crossing(alist, left, mid, right) # 返回最大值 return max(left_sub, right_sub, mid_sub) def max_crossing(alist, left, mid, right): sum = 0 # sys.maxsize int類型最大值: 9223372036854775807 left_sum = -sys.maxsize # 從中間到左邊求和 for i in range(mid, left - 1, -1): sum += alist[i] if sum > left_sum: left_sum = sum sum = 0 right_sum = -sys.maxsize # 從中間到右邊求和 for i in range(mid + 1, right + 1): sum += alist[i] if sum > right_sum: right_sum = sum return left_sum + right_sum alist = [-2, 1, -3, 4, -1, 2, 1, -5, 4] sum = sub_list(alist, 0, len(alist) - 1) print(sum) # 6
動態規劃簡單解法:htm
# O(n) def sub_list(alist): result = -sys.maxsize local = 0 for i in alist: local = max(local + i, i) result = max(result, local) return result alist = [-2, 1, -3, 4, -1, 2, 1, -5, 4] sub_list(alist) # 6
對數組作逆序對計數—距離數組的排序結果還有「多遠」。若是一個數組已經排好序(升序),那麼逆序對個數爲0;
若是數組是降序排列的,則逆序對個數最多。
在形式上,若是有兩個元素a[i], a[j],若是a[i] > a[j] 且 i < j,那麼a[i], a[j]構成一個逆序對。
例如序列[2, 4, 1, 3, 5] 有三個逆序對,分別是(2, 1), (4, 1), (4, 3)
解決思路:
利用歸併排序,只要是左邊大於右邊就有逆序對
# 歸併排序 def merge(left_list, right_list): i, j = 0, 0 result_list = list() # 定義一個計數元素 inv_count inv_count = 0 while i < len(left_list) and j < len(right_list): if left_list[i] < right_list[j]: result_list.append(left_list[i]) i += 1 # 只要right>left則是逆序對,inv_count加len(left_list)-i elif left_list[i] > right_list[j]: result_list.append(right_list[j]) j += 1 inv_count += len(left_list) - i result_list += left_list[i:] result_list += right_list[j:] return result_list, inv_count def count_Inversions(alist): if len(alist) <= 1: return alist, 0 mid = len(alist) // 2 left_list, left_inv = count_Inversions(alist[:mid]) right_list, right_inv = count_Inversions(alist[mid:]) result, count = merge(left_list, right_list) count += left_inv + right_inv return result, count alist = [2, 4, 1, 3, 5] print(count_Inversions(alist)) # [1, 2, 3, 4, 5], 3
以上是一些例題!blog
~>.<!排序
原文出處:https://www.cnblogs.com/pungchur/p/12115016.html遞歸