圖的最短路徑算法
Floyd最短路算法(多源最短路)
參考:https://www.cnblogs.com/ahalei/p/3622328.html

在這里插入圖片描述
上圖中有4個(gè)城市8條公路,公路上的數(shù)字表示這條公路的長(zhǎng)短。請(qǐng)注意這些公路是單向的。我們現(xiàn)在需要求任意兩個(gè)城市之間的最短路程,也就是求任意兩個(gè)點(diǎn)之間的最短路徑。這個(gè)問(wèn)題這也被稱為“多源最短路徑”問(wèn)題。
現(xiàn)在需要一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)圖的信息,我們?nèi)匀豢梢杂靡粋€(gè)4*4的矩陣(二維數(shù)組e)來(lái)存儲(chǔ)。

在這里插入圖片描述
核心代碼:
這段代碼的基本思想就是:
最開(kāi)始只允許經(jīng)過(guò)1號(hào)頂點(diǎn)進(jìn)行中轉(zhuǎn),接下來(lái)只允許經(jīng)過(guò)1和2號(hào)頂點(diǎn)進(jìn)行中轉(zhuǎn)……允許經(jīng)過(guò)1~n號(hào)所有頂點(diǎn)進(jìn)行中轉(zhuǎn),求任意兩點(diǎn)之間的最短路程。用一句話概括就是:從i號(hào)頂點(diǎn)到j(luò)號(hào)頂點(diǎn)只經(jīng)過(guò)前k號(hào)點(diǎn)的最短路程。
Dijkstra最短路算法(單源最短路)
參考:http://blog.51cto.com/ahalei/1387799
指定一個(gè)點(diǎn)(源點(diǎn))到其余各個(gè)頂點(diǎn)的最短路徑,也叫做“單源最短路徑”。例如求下圖中的1號(hào)頂點(diǎn)到2、3、4、5、6號(hào)頂點(diǎn)的最短路徑。

在這里插入圖片描述
仍然使用二維數(shù)組e來(lái)存儲(chǔ)頂點(diǎn)之間邊的關(guān)系,初始值如下。

在這里插入圖片描述
我們還需要用一個(gè)一維數(shù)組dis來(lái)存儲(chǔ)1號(hào)頂點(diǎn)到其余各個(gè)頂點(diǎn)的初始路程,如下。

在這里插入圖片描述
將此時(shí)dis數(shù)組中的值稱為最短路的“估計(jì)值”。
既然是求1號(hào)頂點(diǎn)到其余各個(gè)頂點(diǎn)的最短路程,那就先找一個(gè)離1號(hào)頂點(diǎn)最近的頂點(diǎn)。通過(guò)數(shù)組dis可知當(dāng)前離1號(hào)頂點(diǎn)最近是2號(hào)頂點(diǎn)。當(dāng)選擇了2號(hào)頂點(diǎn)后,dis[2]的值就已經(jīng)從“估計(jì)值”變?yōu)榱?ldquo;確定值”,即1號(hào)頂點(diǎn)到2號(hào)頂點(diǎn)的最短路程就是當(dāng)前dis[2]值。
既然選了2號(hào)頂點(diǎn),接下來(lái)再來(lái)看2號(hào)頂點(diǎn)有哪些出邊呢。有2->3和2->4這兩條邊。先討論通過(guò)2->3這條邊能否讓1號(hào)頂點(diǎn)到3號(hào)頂點(diǎn)的路程變短。也就是說(shuō)現(xiàn)在來(lái)比較dis[3]和dis[2]+e[2][3]的大小。其中dis[3]表示1號(hào)頂點(diǎn)到3號(hào)頂點(diǎn)的路程。dis[2]+e[2][3]中dis[2]表示1號(hào)頂點(diǎn)到2號(hào)頂點(diǎn)的路程,e[2][3]表示2->3這條邊。所以dis[2]+e[2][3]就表示從1號(hào)頂點(diǎn)先到2號(hào)頂點(diǎn),再通過(guò)2->3這條邊,到達(dá)3號(hào)頂點(diǎn)的路程。
這個(gè)過(guò)程有個(gè)專業(yè)術(shù)語(yǔ)叫做“松弛”。松弛完畢之后dis數(shù)組為:

在這里插入圖片描述
接下來(lái),繼續(xù)在剩下的3、4、5和6號(hào)頂點(diǎn)中,選出離1號(hào)頂點(diǎn)最近的頂點(diǎn)4,變?yōu)榇_定值,以此類推。

在這里插入圖片描述
最終dis數(shù)組如下,這便是1號(hào)頂點(diǎn)到其余各個(gè)頂點(diǎn)的最短路徑。

在這里插入圖片描述
- M:邊的數(shù)量
- N:節(jié)點(diǎn)數(shù)量
通過(guò)上面的代碼我們可以看出,這個(gè)算法的時(shí)間復(fù)雜度是O(N^2)。其中每次找到離1號(hào)頂點(diǎn)最近的頂點(diǎn)的時(shí)間復(fù)雜度是O(N)
優(yōu)化:
- 這里我們可以用“堆”(以后再說(shuō))來(lái)優(yōu)化,使得這一部分的時(shí)間復(fù)雜度降低到O(logN)。
- 另外對(duì)于邊數(shù)M少于N^2的稀疏圖來(lái)說(shuō)(我們把M遠(yuǎn)小于N^2的圖稱為稀疏圖,而M相對(duì)較大的圖稱為稠密圖),我們可以用鄰接表來(lái)代替鄰接矩陣,使得整個(gè)時(shí)間復(fù)雜度優(yōu)化到O( (M+N)logN)。
- 請(qǐng)注意!在最壞的情況下M就是N^2,這樣的話MlogN要比N^2還要大。但是大多數(shù)情況下并不會(huì)有那么多邊,因此(M+N)logN要比N2小很多。
用鄰接表代替鄰接矩陣存儲(chǔ)
參考:http://blog.51cto.com/ahalei/1391988
略微難懂,請(qǐng)參考原文
總結(jié)如下:
可以發(fā)現(xiàn)使用鄰接表來(lái)存儲(chǔ)圖的時(shí)間空間復(fù)雜度是O(M),遍歷每一條邊的時(shí)間復(fù)雜度是也是O(M)。如果一個(gè)圖是稀疏圖的話,M要遠(yuǎn)小于N^2。因此稀疏圖選用鄰接表來(lái)存儲(chǔ)要比鄰接矩陣來(lái)存儲(chǔ)要好很多。
漢諾塔
參考圖例:https://www.zhihu.com/question/24385418/answer/89435529
關(guān)鍵代碼:
楊輝三角
參考:https://blog.csdn.net/zmy_3/article/details/51173580
關(guān)鍵代碼(巧用Python中的yield):
注釋:N加上一個(gè)0之后,最后一個(gè)數(shù)是1+0,直接就等于1,不會(huì)有0
回文數(shù)/回文串
解法一:暴力
解法二:分字符串和數(shù)字
斐波拉契數(shù)列(Fibonacci)
最大子序列與最大子矩陣問(wèn)題
數(shù)組的最大子序列問(wèn)題
給定一個(gè)數(shù)組,其中元素有正,也有負(fù),找出其中一個(gè)連續(xù)子序列,使和最大。
參考自己的博客:https://blog.csdn.net/qqxx6661/article/details/78167981
可以理解為動(dòng)態(tài)規(guī)劃:
可以用標(biāo)準(zhǔn)動(dòng)態(tài)規(guī)劃求解也可以用直接方法求解,但思路都是動(dòng)態(tài)規(guī)劃
最大子矩陣問(wèn)題
給定一個(gè)矩陣(二維數(shù)組),其中數(shù)據(jù)有大有小,請(qǐng)找一個(gè)子矩陣,使得子矩陣的和最大,并輸出這個(gè)和。
參考:https://blog.csdn.net/kavu1/article/details/50547401
思路:
原始矩陣可以是二維的。假設(shè)原始矩陣是一個(gè)3 * n 的矩陣,那么它的子矩陣可以是 1 * k, 2 * k, 3 * k,(1 <= k <= n)。 如果是1*K,這里有3種情況:子矩陣在第一行,子矩陣在第二行,子矩陣在第三行。如果是 2 * k,這里有兩種情況,子矩陣在第一、二行,子矩陣在第二、三行。如果是3 * k,只有一種情況。
為了能夠找出最大的子矩陣,我們需要考慮所有的情況。假設(shè)這個(gè)子矩陣是 2 * k, 也就是說(shuō)它只有兩行,要找出最大子矩陣,我們要從左到右不斷的遍歷才能找出在這種情況下的最大子矩陣。如果我們把這兩行上下相加,情況就和求“最大子段和問(wèn)題” 又是一樣的了。
KMP算法
原理參考:
http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
移動(dòng)位數(shù) = 已匹配的字符數(shù) - 對(duì)應(yīng)的部分匹配值
"部分匹配值"就是"前綴"和"后綴"的最長(zhǎng)的共有元素的長(zhǎng)度。以"ABCDABD"為例,
實(shí)現(xiàn)參考自己的博客:
https://blog.csdn.net/qqxx6661/article/details/79583707
LCS/最長(zhǎng)公共子序列/最長(zhǎng)公共子串
參考自己的博客:
https://blog.csdn.net/qqxx6661/article/details/79587392
最長(zhǎng)公共子序列LCS
動(dòng)態(tài)規(guī)劃狀態(tài)轉(zhuǎn)移方程式

在這里插入圖片描述
最長(zhǎng)公共回文子串
動(dòng)態(tài)規(guī)劃狀態(tài)轉(zhuǎn)移方程式

在這里插入圖片描述
求圓周率

在這里插入圖片描述
大數(shù)問(wèn)題(加減乘除)
加法
對(duì)應(yīng)位置相加,考慮進(jìn)位,前面不夠補(bǔ)0
減法
和相加十分類似
就是按照我們手寫(xiě)除法時(shí)的方法,兩個(gè)數(shù)字末位對(duì)齊,從后開(kāi)始,按位相減,不夠減時(shí)向前位借一。
最終結(jié)果需要去除首端的0.如果所有位都是0,則返回0。
乘法
大數(shù)乘法問(wèn)題及其高效算法:
https://blog.csdn.net/u010983881/article/details/77503519
方法:
- 模擬小學(xué)乘法:最簡(jiǎn)單的乘法豎式手算的累加型;
自己實(shí)現(xiàn)的:https://blog.csdn.net/qqxx6661/article/details/78119074
- 分治乘法:最簡(jiǎn)單的是Karatsuba乘法,一般化以后有Toom-Cook乘法;
見(jiàn)下方
- 快速傅里葉變換FFT:(為了避免精度問(wèn)題,可以改用快速數(shù)論變換FNTT),時(shí)間復(fù)雜度O(N lgN lglgN)。具體可參照Schönhage–Strassen algorithm;
- 中國(guó)剩余定理:把每個(gè)數(shù)分解到一些互素的模上,然后每個(gè)同余方程對(duì)應(yīng)乘起來(lái)就行;
- Furer’s algorithm:在漸進(jìn)意義上FNTT還快的算法。不過(guò)好像不太實(shí)用,本文就不作介紹了。大家可以參考維基百科
方法2:
參考:
https://blog.csdn.net/jeffleo/article/details/53446095
Karatsuba乘法(公式和下面代碼實(shí)現(xiàn)的不同,但是原理相同,可以直接背下方代碼)

在這里插入圖片描述
核心語(yǔ)句:
完整代碼:
除法
Leetcode原題(用位運(yùn)算加速了手動(dòng)除法)
https://blog.csdn.net/qqxx6661/article/details/79723357
為了加速運(yùn)算,可以依次將被除數(shù)減去1,2,4,8,..倍的除數(shù),本質(zhì)上只是用位運(yùn)算加速了手動(dòng)除法
計(jì)算機(jī)計(jì)算乘除法的原理
位運(yùn)算除法
https://blog.csdn.net/zdavb/article/details/47108505
最小生成樹(shù)
圖解Prim算法和Kruskal算法:
https://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html
兩種方法的時(shí)間復(fù)雜度
Prim:
這里記頂點(diǎn)數(shù)v,邊數(shù)e
- 鄰接矩陣:O(v2)
- 鄰接表:O(elog2v)
Kruskal:
elog2e e為圖中的邊數(shù)