日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

算法图解--python

發(fā)布時(shí)間:2023/12/10 python 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法图解--python 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最近拿算法圖解重新溫習(xí)了一下算法,這本書真的非常適合入門,把比較簡單算法細(xì)節(jié)和思路講的非常清楚。

果然入門計(jì)算機(jī)語言就該學(xué)python。 大學(xué)里面一上來就C++太苦逼了。

? ? ? ? 然后是第一次強(qiáng)烈的感受到Python解題的魅力。之前學(xué)python的時(shí)候,覺得不用定義就直接使用很變扭,還有就是可以靈活的使用各種數(shù)據(jù)結(jié)構(gòu),也是有點(diǎn)不適應(yīng)。因?yàn)橐婚_始學(xué)的就是C++,之前算法和數(shù)據(jù)結(jié)構(gòu)都是用C++寫的,后面工作用Java。Python還沒拿來用過。某神說,leetcode里面排名考前的都是用python提交的,因?yàn)閷懫饋砀鷤未a差不多,有思路就好了,不用像c++、java那樣考慮語言的特性。

? ? ? ? 對于它們的語言特性最近的感受就是:Python就像塑料袋,什么東西都可以往里面塞,不怕變形,兼容性超好;Java像紙箱,類得寫好了才能生成對象;C++跟java差不多,像木箱吧哈哈哈。

大概總結(jié)一下里面提到的算法吧:

一、算法簡介

1.1二分查找 :

一個(gè)有序數(shù)組中找一個(gè)數(shù)的位置(對應(yīng)該數(shù)字所在數(shù)組下標(biāo)index)。

def binary_search(list, item):low = 0high = len(list) - 1while low <= high:mid = int((low + high) / 2)guess = list[mid]if guess == item:return midif guess > item:high = mid - 1else:low = mid + 1return Nonemy_list = [1, 3, 5, 7, 9]print(binary_search(my_list, 3)) # => 1 print(binary_search(my_list, -1)) # => None
  • 也可用遞歸實(shí)現(xiàn)
  • 操作對象:數(shù)組
  • 使用前提:有序的數(shù)組
  • 性能方面:時(shí)間復(fù)雜度O(logn)

1.2 旅行商問題:

旅行商前往n個(gè)城市,確保旅程最短。求可能的排序:n!種可能。

?

二、選擇排序

2.1 數(shù)組和鏈表

數(shù)組:連續(xù)存儲(chǔ)在硬盤中;鏈表:分散存儲(chǔ)在硬盤中;

?

2.2 選擇排序:將數(shù)組元素按照從小到大的順序排序,每次從數(shù)組中取出最小值

def findSmallest(arr):smallest = arr[0]smallest_index = 0for i in range(1, len(arr)):if arr[i] < smallest:smallest = arr[i]smallest_index = ireturn smallest_indexdef selectionSort(arr):newArr = []for i in range(len(arr)):smallest = findSmallest(arr)newArr.append(arr.pop(smallest))return newArrprint(selectionSort([5, 3, 6, 2, 10])) #[2, 3, 5, 6, 10]

?

三、遞歸----一種優(yōu)雅的問題解決方法

適用遞歸的算法要滿足:

  • 基限條件(即返回的條件)
  • 遞歸條件(調(diào)用遞歸函數(shù))

特點(diǎn):

自己調(diào)用自己,調(diào)用棧在內(nèi)存疊加,如果沒有返回條件,將無限循環(huán)調(diào)用,占用大量內(nèi)存,最終爆棧終止進(jìn)程。

?

還有一種高級一點(diǎn)的遞歸:

尾遞歸 (將結(jié)果也放入函數(shù)參數(shù),內(nèi)存里面調(diào)用棧只有一個(gè)當(dāng)前運(yùn)行的函數(shù)進(jìn)程)

舉個(gè)簡單的例子: 階乘f(n) = n!

def fact(x): #遞歸if x == 1:return 1else:return x * fact(x-1) #注意這里跟尾遞歸不同#尾遞歸 def factorial(x,result): if x == 1:return resultelse:return factorial(x-1,x*result)if __name__ == '__main__':print(fact(5)) #5*4*3*2*1 = 120print(factorial(5,1)) #120

?

四、快速排序 (分而治之策略)

  • 每次選取數(shù)組中一個(gè)元素x當(dāng)作分水嶺(一般選取第一個(gè)元素):[小于元素x的數(shù)組]+[x]+[大于元素x的數(shù)組],然后遞歸調(diào)用,直到最后處理的數(shù)組元素只剩下零個(gè)或者一個(gè)
  • 平均時(shí)間復(fù)雜度O(nlogn)
  • 最差情況時(shí)間復(fù)雜度O(n^2)? ?(出現(xiàn)這個(gè)情況是:快排的數(shù)組本來就是有序的(順序/倒序),選取的元素又是開頭第一個(gè)的話,每次變成只能處理一側(cè)的數(shù)組了。 改善:可以選取數(shù)組中間的元素當(dāng)作分水嶺pivot,只有兩邊的元素就都能均勻處理了)
#!/usr/bin/pythondef quicksort(array):if len(array) < 2:return arrayelse:pivot = array[0]less = [i for i in array[1:] if i <= pivot] #超級像偽代碼!print(less)greater = [i for i in array[1:] if i > pivot]print(greater)return quicksort(less) + [pivot] + quicksort(greater)if __name__ == '__main__':print(quicksort([7,1,10,5,3,2,6]))''' [1, 5, 3, 2, 6] [10] [] [5, 3, 2, 6] [3, 2] [6] [2] [] [1, 2, 3, 5, 6, 7, 10] '''

?

到目前算法為止,復(fù)雜度對比:

?

排序到算法有:

冒泡排序,選擇排序,快速排序,歸并排序,堆排序(感興趣到小伙伴可以自己去搜索)

?

下面列出冒泡排序和歸并排序算法:

#冒泡排序,每次尋找最小到元素往前排,就像汽水從下往上冒一樣。所以叫冒泡排序啦 def simpleSort(array):for i in range(len(array)-1):for j in range(i,len(array)):if array[i] > array[j]:temp = array[i]array[i] = array[j]array[j] = tempreturn arrayprint(simpleSort([9,8,6,7,4,5,3,11,2])) #[2, 3, 4, 5, 6, 7, 8, 9, 11]
  • 冒泡排序時(shí)間復(fù)雜度O(n^2)
  • 兩個(gè)for循環(huán)搞定,每一輪for循環(huán)找到一個(gè)最小值。for循環(huán)兩兩元素對比交換

?

歸并排序:

def mergeSort(array):if len(array) < 2:return arrayelse:mid = int(len(array)/2)left = mergeSort(array[:mid])right = mergeSort(array[mid:])return merge(left, right)def merge(left, right): #并兩個(gè)已排序好的列表,產(chǎn)生一個(gè)新的已排序好的列表result = [] # 新的已排序好的列表i = 0 # 下標(biāo)j = 0# 對兩個(gè)列表中的元素 兩兩對比# 將最小的元素,放到result中,并對當(dāng)前列表下標(biāo)加1while i < len(left) and j < len(right):if left[i] <= right[j]:result.append(left[i])i += 1else:result.append(right[j])j += 1# 此時(shí)left或者right其中一個(gè)已經(jīng)添加完畢,剩下的就全部加到result后面即可 result += left[i:] result += right[j:]return resultarray = [9,5,3,0,6,2,7,1,4,8] result = mergeSort(array) print('排序后:',result) #排序后: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  • 歸并排序時(shí)間復(fù)雜度是O(nlogn)
  • 最壞情況也是O(nlogn)
  • 歸并排序采用先分后總的方式,先按中間分,分到數(shù)組最后只有一個(gè)元素為止,最后兩兩合并。有點(diǎn)mapReduce的味道。

?

五、散列表(Hash)

散列函數(shù):?散列函數(shù)是這樣的函數(shù),即無論你給它什么數(shù)據(jù),它都還你一個(gè)數(shù)字。

模擬映射關(guān)系

散列(哈希)函數(shù)應(yīng)用廣泛:

  • 快速查找
  • 文件安全性傳輸交驗(yàn)
  • 可以防止重復(fù) (一旦發(fā)現(xiàn)重復(fù),該哈希函數(shù)就不安全了。也就是說被破譯了。)
  • ?緩存/ 記住數(shù)據(jù),以免服務(wù)器再通過處理來生成它們。

性能:

  • ?散列表的填裝因子 = (散列表包含的元素?cái)?shù))/(位置總數(shù))
  • ?填裝因子越低,發(fā)生沖突的可能性越小,散列表的性能越高。一個(gè)不錯(cuò)的經(jīng)驗(yàn)規(guī)則是:一旦填裝因子大于0.7 ,就調(diào)整散列表的長度。

良好的散列函數(shù)讓數(shù)組中的值呈均勻分布。

糟糕的散列函數(shù)讓值扎堆,導(dǎo)致大量的沖突。

?

六、廣度優(yōu)先搜索?(breadth-first search ,BFS )?

?廣度優(yōu)先搜索是一種用于圖的查找算法,可幫助回答兩類問題:

第一類問題:從節(jié)點(diǎn)A 出發(fā),有前往節(jié)點(diǎn)B 的路徑嗎?

?第二類問題:從節(jié)點(diǎn)A 出發(fā),前往節(jié)點(diǎn)B 的哪條路徑最短?

  • 廣搜采用雙端隊(duì)列
  • 處理過程中,將所有有關(guān)的節(jié)點(diǎn)都添加到處理隊(duì)列中
  • ?非加權(quán)圖(無向圖)中查找最短路徑

看如下例子:從你的朋友關(guān)系網(wǎng)中,找出一個(gè)芒果銷售商。(假設(shè)芒果銷售商名字是以m結(jié)尾)

?

from collections import deque#需編寫函數(shù)person_is_seller,判斷一個(gè)人是不是芒果銷售商,如下所示。 def person_is_seller(name):return name[-1] == 'm' #這個(gè)函數(shù)檢查人的姓名是否以m結(jié)尾:如果是,他就是芒果銷售商。。def bfs(graph,name):search_queue = deque()search_queue += graph[name]#graph["you"]是一個(gè)數(shù)組,其中包含你的所有鄰居,如["alice", "bob","claire"]。這些鄰居都將加入到搜索隊(duì)列中。searched =[]while search_queue:person = search_queue.popleft()if not person in searched:if person_is_seller(person):print(person + " is a mango seller!")return Trueelse:search_queue += graph[person]searched.append(person)return Falseif __name__=='__main__':graph = {}graph["you"] = ["alice", "bob", "claire"]graph["bob"] = ["anuj", "peggy"]graph["alice"] = ["peggy"]graph["claire"] = ["thom", "jonny" ]graph["anuj"] = []graph["peggy"] = [] graph["thom"] = []graph["jonny"] = []print(graph) ''' {'you': ['alice', 'bob', 'claire'], 'bob': ['anuj', 'peggy'], 'alice': ['peggy'], 'claire': ['thom', 'jonny'], 'anuj': [], 'peggy': [], 'thom': [], 'jonny': []} '''bfs(graph,"you") #thom is a mango seller!

?

七、狄克斯特拉算法(?Dijkstra’s algorithm)

  • 可以處理:有向無環(huán)圖(directed acyclic graph,DAG)
  • ?加權(quán)圖中查找最短路徑

  • ?不能將狄克斯特拉算法用于包含負(fù)權(quán)邊的圖。在包含負(fù)權(quán)邊的圖中,要找出最短路徑,可使用另一種算法—— 貝爾曼? 福德算法(Bellman-Ford algorithm)

def find_lowest_cost_node(costs,processed):lowest_cost = float("inf")lowest_cost_node = Nonefor node in costs:cost = costs[node]if cost < lowest_cost and node not in processed:lowest_cost = costlowest_cost_node = nodereturn lowest_cost_nodedef dijkstra(graph,costs,parents):processed = []node = find_lowest_cost_node(costs,processed)while node is not None:cost=costs[node]neighbors=graph[node]for n in neighbors.keys():new_cost = cost + neighbors[n]if costs[n]>new_cost:costs[n]=new_costparents[n]=nodeprocessed.append(node)node = find_lowest_cost_node(costs,processed)return costs,parentsif __name__ == '__main__':graph = {}graph["start"] = {}graph["start"]["a"] = 6graph["start"]["b"] = 6graph["a"] = {}graph["a"]["fin"] = 1graph["b"] = {}graph["b"]["a"] = 3graph["b"]["fin"] = 5graph["fin"] = {}infinity = float("inf")costs = {}costs["a"] = 6costs["b"] = 2costs["fin"] = infinityparents={}parents["a"]="start"parents["b"] = "start"parents["fin"] = Nonecosts,parents = dijkstra(graph,costs,parents)print(costs) #{'a': 5, 'b': 2, 'fin': 6}print(parents) #{'a': 'b', 'b': 'start', 'fin': 'a'}

?

八、貪婪算法(貪心算法)

  • ?貪婪算法易于實(shí)現(xiàn)、運(yùn)行速度快,是不錯(cuò)的近似算
  • ?貪婪算法尋找局部最優(yōu)解,企圖以這種方式獲得全局最優(yōu)解

?

可解決:

  • 調(diào)度問題
  • 背包問題
  • 集合覆蓋問題

stations = {} stations["kone"] = set(["id", "nv", "ut"]) stations["ktwo"] = set(["wa", "id", "mt"]) stations["kthree"] = set(["or", "nv", "ca"]) stations["kfour"] = set(["nv", "ut"]) stations["kfive"] = set(["ca", "az"]) print(stations) ''' {'kone': {'id', 'nv', 'ut'}, 'ktwo': {'wa', 'mt', 'id'}, 'kthree': {'ca', 'or', 'nv'}, 'kfour': {'nv', 'ut'}, 'kfive': {'ca', 'az'}} '''states_needed = set(['id', 'or', 'ut', 'wa', 'ca', 'az', 'nv', 'mt']) print(states_needed)final_stations = set()while states_needed:best_station = Nonestates_covered = set()for station, states in stations.items():covered = states_needed & statesif len(covered) > len(states_covered):best_station = stationstates_covered = coveredstates_needed -= states_coveredfinal_stations.add(best_station)print(final_stations) #{'kfive', 'kthree', 'kone', 'ktwo'} 選擇1235

?

九、動(dòng)態(tài)規(guī)劃:將問題分成小問題,并先著手解決這些小問題

9.1動(dòng)態(tài)規(guī)劃,都可以畫網(wǎng)格解決!

背包問題

?假設(shè)你是個(gè)小偷,背著一個(gè)可裝4 磅東西的背包。

你可盜竊的商品有如下3 件:

音響,3000美元,4磅

筆記本電腦,2000美元,3磅

吉他,1500美元,1磅

?每個(gè)動(dòng)態(tài)規(guī)劃算法都從一個(gè)網(wǎng)格開始,背包問題的網(wǎng)格如:

最終結(jié)果:

def bag(goods,size):cell = [[0 for col in range(size)] for row in range(len(goods))] package_size= [i+1 for i in range(size)] for j in range(size):if(goods[0][1]<=package_size[j]):cell[0][j] = goods[0][0]for i in range(1,len(goods)):for j in range(size):if (package_size[j]-goods[i][1]>0) and (goods[i][0] + cell[i-1][package_size[j]-1-goods[i][1]]) > cell[i-1][j]:cell[i][j] = goods[i][0] + cell[i-1][package_size[j]-goods[i][1]-1]elif (package_size[j]-goods[i][1]==0) and (goods[i][0] > cell[i-1][j]): cell[i][j] = goods[i][0]else:cell[i][j] = cell[i-1][j]print(cell) #[[1500, 1500, 1500, 1500], [1500, 1500, 1500, 3000], [1500, 1500, 2000, 3500]]return cell[len(goods) - 1][size - 1]if __name__ == '__main__':goods = [[1500,1],[3000,4],[2000,3]]print(bag(goods,4)) #3500

?動(dòng)態(tài)規(guī)劃功能強(qiáng)大,它能夠解決子問題并使用這些答案來解決大問題。但僅當(dāng)每個(gè)子問題都是離散的,即不依賴于其他子問題時(shí),動(dòng)態(tài)規(guī)劃才管用。

最優(yōu)解可能導(dǎo)致背包沒裝滿。

?

9.2 最長公共子串

?

9.3 最長公共子序列

?

十、K最近鄰算法(KNN):?KNN用于分類和回歸,需要考慮最近的鄰居

?要計(jì)算兩點(diǎn)的距離,可使用畢達(dá)哥拉斯公式:

?KNN算法真的是很有用,堪稱你進(jìn)入神奇的機(jī)器學(xué)習(xí)領(lǐng)域的領(lǐng)路人!

?使用KNN 來做兩項(xiàng)基本工作—— 分類和回歸:

?? 分類就是編組;

?? 回歸就是預(yù)測結(jié)果(如一個(gè)數(shù)字)

?特征抽取意味著將物品(如水果或用戶)轉(zhuǎn)換為一系列可比較的數(shù)字

?

?OCR指的是光學(xué)字符識(shí)別( optical character recognition),這意味著你可拍攝印刷頁面的照片,

計(jì)算機(jī)將自動(dòng)識(shí)別出其中的文字。??一般而言,OCR 算法提取線段、點(diǎn)和曲線等特征

?

?垃圾郵件過濾器使用一種簡單算法——樸素貝葉斯分類器 (Naive Bayes classifier )

?樸素貝葉斯分類器能計(jì)算出郵件為垃圾郵件的概率,其應(yīng)用領(lǐng)域與KNN 相似。

?

?

十一、其他算法

11.1 樹

? ? ? ? 二叉查找樹:?平均訪問時(shí)間也為O(log n)

?B樹是一種特殊的二叉樹,數(shù)據(jù)庫常用它來存儲(chǔ)數(shù)據(jù)

?如果你對數(shù)據(jù)庫或高級數(shù)據(jù)結(jié)構(gòu)感興趣,請研究如下數(shù)據(jù)結(jié)構(gòu):B 樹,紅黑樹,堆,伸展樹。

11.2 反向索引:一個(gè)散列表,將單詞映射到包含它的頁面。這種數(shù)據(jù)結(jié)構(gòu)被稱為反向索引 (inverted index ),常用于創(chuàng)

建搜索引擎

11.3 傅立葉變換(分離數(shù)字信號,用sin+cos疊加):?給定一首歌曲,傅里葉變換能夠?qū)⑵渲械母鞣N頻率分離出來。

?

?與可擴(kuò)展性和海量數(shù)據(jù)處理相關(guān):

11.4并行算法(?要改善性能和可擴(kuò)展性,并行算法可能是不錯(cuò)的選擇!)

11.5?MapReduce(?分布式算法)

?映射(map )函數(shù)和歸并(reduce )函數(shù)

?映射是將一個(gè)數(shù)組轉(zhuǎn)換為另一個(gè)數(shù)組

?歸并是將一個(gè)數(shù)組轉(zhuǎn)換為一個(gè)元素

?

1.6 布隆過濾器和HyperLogLog

?

11.7 SHA 算法(?散列函數(shù)是安全散列算法(secure hash algorithm ,SHA )函數(shù))

? ?給定一個(gè)字符串,SHA返回其散列值。

可用于比較文件/檢查密碼

?

11.8 局部敏感的散列算法

?有時(shí)候,你希望結(jié)果相反,即希望散列函數(shù)是局部敏感的。在這種情況下,可使用Simhash

?

11.9 Diffie-Hellman 密鑰交換(?公鑰和私)

?Diffie-Hellman算法解決了如下兩個(gè)問題:

? 雙方無需知道加密算法。他們不必會(huì)面協(xié)商要使用的加密算法。

? 要破解加密的消息比登天還難。

?

11.10 線性規(guī)劃 (初中知識(shí)。。常考題)

?目標(biāo)是利潤最大化,而約束條件是擁有的原材料數(shù)量。

?線性規(guī)劃使用Simplex 算法,?這個(gè)算法很復(fù)雜(最優(yōu)化)

?

?

?

歡迎關(guān)注本人微信公眾號:

?

?

?

?

?

?

?

總結(jié)

以上是生活随笔為你收集整理的算法图解--python的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。