算法數據,數據結構,python概述

問題一:1+2+3+4+5+…+10000=?

第一種解法:

1+2=3,3+3=6,6+4=10,10+5=15…

這是要算到猴年馬月的節奏呀 果斷棄之

第二種解法:

聰明的高斯,這樣玩:

(1+10000)×10000÷2=50005000 (1+10000)\times10000\div2=50005000(1+10000)×10000÷2=50005000

在這一問題的解答上,高斯的方法真香!

問題二:冬天裏,你和小紅玩猜數字,小紅隨便想一個1~100的數字。你的目標是以最少的次數猜到這個數字。你每次猜測後,小紅會說小了、大了或對了。在10次內猜對了,小紅就答應今晚用你暖牀。是不是聽着很刺激

第一種解法:

你從1開始依次往上猜,猜測過程會是這樣,小紅皺着眉不斷說小了

這是簡單查找,更準確的說法是傻找 。每次猜測都只能排除一個數字。如果小紅想的數字是99,你得猜99次才能猜到!,註定今晚你和小紅無緣了

第二種解法:你從50開始,小紅笑着說小了,你接着說75…

你每次猜測的是中間的數字,從而每次都將餘下的數字排除一半。接下來,你猜63(50和75中間的數字)…這就是二分查找,每次猜測排除的數字個數如下:

不管小紅心裏想的是哪個數字,你在7次之內都能猜到,因爲每次猜測都將排除很多數字!恭喜你,小紅今晚是你的人了。

解析:對於包含n 個元素的有序列表,用二分查找最多需要log2n log_2 nlog2n步1,而簡單查找最多需要n 步。

二分查找的python實現

def binary_search(list1, item):

low = 0 # low和high用於跟蹤要在其中查找的列表部分

high = len(list1) - 1

while low <= high:

mid = (low + high) // 2

guess = list1[mid]

if guess == item: # 猜對了

return mid # 返回位置

elif guess > item: # 猜大了

high = mid - 1

else: # 猜小了

low = mid + 1

return None # 沒有找到

my_list = [i for i in range(1,100)] # 列表推導式生成0-100個數

print(binary_search(my_list, 3)) # 別忘了索引從0開始

回到前面的二分查找。使用它可節省多少時間呢?簡單查找逐個地檢查數字,如果列表包含100個數字,最多需要猜100次。如果列表包含40億個數字,最多需要猜40億次。換言之,最多需要猜測的次數與列表長度相同,這被稱爲線性時間(linear time)。

二分查找則不同。如果列表包含100個元素,最多要猜7次;如果列表包含40億個數字,最多需猜32次。厲害吧?二分查找的運行時間爲對數時間 (或log loglog時間)。

算法

在計算機領域,我們同樣會遇到各種高效和拙劣的算法。衡量算法好壞的重要標準有兩個。通常指最糟的情形下的:

時間複雜度(採用大O表示法)

空間複雜度(採用大O表示法)

理解:小明和小剛都是初入IT的新人,一天老闆給他們佈置了同一個需求讓他們用代碼實現出來,小明的代碼運行一次要花100ms,佔用內存5MB。小剛的代碼運行一次要花100s,佔用內存500MB。於是……小剛第二天就從公司消失了

你經常會遇到的5種大O運行時間:

O (logn log nlogn),也叫對數時間,這樣的算法包括二分查找

O (n),也叫線性時間,這樣的算法包括簡單查找

O (n∗logn n * log nn∗logn),這樣的算法包括快速排序——一種速度較快的排序算法。

O (n2 n ^2n2),這樣的算法包括選擇排序——一種速度較慢的排序算法。

O (n! n !n!),這樣的算法包括旅行商問題的解決方案——一種非常慢的算法.

假設你要繪製一個包含16格的網格,且有5種不同的算法可供選擇:

時間複雜度的概念明白了,那空間複雜度呢:

問題三:給出下圖所示的n個整數,其中有兩個整數是重複的,要求找出這兩個重複的整數。

第一種解法:

你採用雙重循環,遍歷整個數列,每遍歷到一個新的整數就開始回顧之前遍歷過的所有整數,看看這些整數裏有沒有與之數值相同的,第1步,遍歷整數3,前面沒有數字,所以無須回顧比較。第2步,遍歷整數1,回顧前面的數字3,沒有發現重複數字。後續步驟類似,一直遍歷到最後的整數2,發現和前面的整數2重複。

這個算法的時間複雜度是O(n2) O(n^2)O(n2)

第二種解法:

當你遍歷整個數列時,每遍歷一個整數,就把該整數存儲起來,就像放到字典中

一樣。當遍歷下一個整數時,不必再慢慢向前回溯比較,而直接去“字典”中查找,看看有沒有對應的整數即可。“字典”左側的Key代表整數的值,“字典”右側的Value代表該整數出現的次數(也可以只記錄Key)。當遍歷到最後一個整數2時,從“字典”中可以輕鬆找到2曾經出現過,問題也就迎刃而解了。

讀寫“字典”本身的時間複雜度是O(1) O(1)O(1),所以整個算法的時間複雜度是O(n) O(n)O(n)

第二種解法採用的這個所謂的“字典”,是一種特殊的數據結構,叫作散列表。這個數據結構需要開闢一定的內存空間來存儲有用的數據信息。

計算機的內存空間是有限的,在時間複雜度相同的情況下,算法佔用的內存空間自然是越小越好。如何描述一個算法佔用的內存空間的大小呢?這就用到了算法的另一個重要指標——空間複雜度(space complexity)。

常量空間,當算法的存儲空間大小固定,和輸入規模沒有直接的關係時,空間複雜度記作O(1) O(1)O(1)

線性空間,當算法分配的空間是一個線性的集合(如數組),並且集合大小和輸入規模n成正比時,空間複雜度記作O(n) O(n)O(n)

二維空間,當算法分配的空間是一個二維數組集合,並且集合的長度和寬度都與輸入規模n成正比時,空間複雜度記作O(n2) O(n^2)O(n2)

遞歸空間,遞歸是一個比較特殊的場景。雖然遞歸代碼中並沒有顯式地聲明變量或集合,但是計算機在執行程序時,會專門分配一塊內存,用來存儲“方法調用棧”。執行遞歸操作所需要的內存空間和遞歸的深度成正比。純粹的遞歸操作的空間複雜度也是線性的,如果遞歸的深度是n,那麼空間複雜度就是O(n) O(n)O(n)。

時間與空間的取捨:

人們之所以花大力氣去評估算法的時間複雜度和空間複雜度,其根本原因是計算機的運算速度和空間資源是有限的。雖然目前計算機的CPU處理速度不斷飆升,內存和硬盤空間也越來越大,但是面對龐大而複雜的數據和業務,我們仍然要精打細算,選擇最有效的利用方式。

在尋找重複整數的問題三中,雙重循環的時間複雜度是O(n2) O(n^2)O(n2),空間複雜度是O(1) O(1)O(1),這屬於犧牲時間來換取空間的情況。相反,字典法的空間複雜度是O(n) O(n)O(n),時間複雜度是O(n) O(n)O(n),這屬於犧牲空間來換取時間的情況。在絕大多數時候,時間複雜度更爲重要一些,我們寧可多分配一些內存空間,也要提升程序的執行速度。

數據結構

算法的概念理解清楚了,下面就是數據結構。如果把算法比喻成美麗靈動的舞者,那麼數據結構就是舞者腳下廣闊而堅實的舞臺。數據結構,對應的英文單詞是data structure,是數據的組織、管理和存儲格式,其使用目的是爲了高效地訪問和修改數據。

常見的數據結構:

線性結構,線性結構是最簡單的數據結構,包括數組、鏈表,以及由它們衍生出來的棧、隊列、哈希表。

樹是相對複雜的數據結構,其中比較有代表性的是二叉樹,由它又衍生出了二叉堆之類的數據結構。

圖是更爲複雜的數據結構,因爲在圖中會呈現出多對多的關聯關係。

  • 除上述所列的幾種基本數據結構以外,還有一些其他的千奇百怪的數據結構。它們由基本數據結構變形而來,用於解決某些特定問題,如跳錶、哈希鏈表、位圖等。

推薦我們的Python學習扣qun:784758214 ,看看前輩們是如何學習的!從基礎的python腳本到web開發、爬蟲、django、數據挖掘等【PDF,實戰源碼】,零基礎到項目實戰的資料都有整理。送給每一位python的小夥伴!每天都有大牛定時講解Python技術,分享一些學習的方法和需要注意的小細節,點擊加入我們的 python學習者聚集地

發佈了54 篇原創文章 · 獲贊 68 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章