左程云算法学习笔记
左程云算法筆記
- 學習簡介
- 認識復雜度,對數器,二分法與異或
- 線段樹(區間修改樹)
- 比較器與堆
- 堆
- 比較器
- 鏈表常見面試題
- 二叉樹的基本算法
- 二叉樹的遞歸套路
- 貪心算法(不全)
- 并查集(不全)
- 圖的算法
- 暴力遞歸
- 暴力遞歸到動態規劃
學習簡介
2021寒假學習算法,在B站看到了左程云的算法,看了一下還不錯。
認識復雜度,對數器,二分法與異或
你好! 這是你第一次使用 Markdown編輯器 所展示的歡迎頁。如果你想學習如何使用Markdown編輯器, 可以仔細閱讀這篇文章,了解一下Markdown的基本語法知識。
線段樹(區間修改樹)
線段樹定義:給定一個數組,使其實現以下在區間內的方法,且方法的時間復雜度都為O(logN)
線段樹的創建:將長度為N的數組按二分法分下來,建立一顆二分樹,將對應的二分區間存在一個新建的數組中,新建數組長度為4N,且0位置廢棄
線段樹代碼:
初始階段,將sum數組中的值填好
l和r為區間的左右端點,rt為sum數組的下標即二分樹的下標
layz更新:從上到下找,如果二分區間包含于想要加的數組,則停止繼續向下,繼續左右方向的尋找,直到找全為止,機制為能攬則攬,攬不住就下發給能攬的區間,懶任務躲不過了(也就是當前任務懶不住了),就會散發他懶的所有任務
layz代碼:
update:
query:
感覺我需要用好長好長時間去理解了
比較器與堆
堆
定義:堆通常是一個可以被看做一棵完全二叉樹的數組對象。堆又有其特性,分為大根堆(上面的下面的大)和小根堆(下面的上面的大)
有時候下標會從"1"開始,因為位運算比乘法快
創建大根堆代碼:
當有N個數時,樹的高度為logN。
當你想刪掉堆頂元素時:
heapify操作:
拿新堆頂與下層元素中的最大值比較,小了就交換,繼續比較與交換
上述代碼:
給一個無序的數組,使用堆來使它變得有序:
優化構建大根堆算法:時間復雜度為 O(N) 從下依次往上判斷是否為大根堆,若否,則與它的較大的子結點交換
系統自帶的堆:
看似優先隊列,實則小根堆。
例題:
若k為5,則先讓k+1個數構建小根堆,因為第0號位置只有可能是0-5上的數,然后彈出最小值,繼續加上6號位置,繼續上述操作
時間復雜度為O(N*logk)
比較器
代碼
和python中的自定義排序函數類似,自己定義函數,定義比較規則
創建大根堆:
返回負數時o1放在上面
手動建堆:
在修改值的時候,可能會上升也可能會下沉,所以heapInsert或者heapify只會中一個,所以都寫,第一個沒中出來看第二個
鏈表常見面試題
1、常用數據結構和技巧
2、快慢指針
4道題
都是慢指針走一步,快指針走兩步,但是根據要求不同,細節處理方面也不同
(1)代碼展示
(2)代碼展示
(3)代碼展示
(4)代碼展示
2、
1、可以用棧來解決,遍歷一個往棧里放一個,遍歷完之后再彈出,或者先入棧再彈,遍歷一個彈一個看是否一樣。
代碼展示:
第一種方法(用N個空間):
第二種方法(用N/2個空間):
使用快慢指針,找到中點,奇數個找中點,偶數個找中點的前一個,當快指針遍歷完時,將滿指針之后的元素入棧,再一一彈出與滿指針前面的元素比較
第三種方法(面試用):使用快慢指針,當快指針走完時,將滿指針到快指針逆序,然后兩邊同時向后移動比較
代碼展示:
3、
題目解釋:
代碼展示:
先將其存入數組中,對數組使用partition方法將其按傳的值分割,最后再將其串起來
第三種方法(面試用):
定義六個引用,sH和sT為小于傳參的頭指針和尾指針,eH和eT為等于傳參的頭指針和尾指針,bH和bT為大于傳參的頭指針和尾指針,遍歷一個賦一個,最后再連起來,每一步操作都是O(1),整體就是O(N)
代碼展示:
4、
第一種方法:
先用哈希表(字典)存儲節點,key為原節點,value為克隆節點,先看節點,通過1找到1’,然后通過1.next找到1’next,通過1.rand找到1’.rand,以此類推,最后返回頭節點
代碼展示:
第二種方法:
第一次遍歷1,將1’節點插在1之后,再遍歷2,將2‘插在2之后,以此類推,插完之后,再一對一對的取值,將1.rand的值賦予1’.rand,以此類推,最后再分離
代碼展示:
5、
如何找鏈表中的環開始點:
1、用set集合,遍歷一個往set里放一個,在放的同時看遍歷的節點set集合里是否已經存在,第一個重復的節點即為環開始的點
2、快慢指針法:先讓滿指針走1步,快指針走兩步,第一次相遇說明有環。相遇后讓快指針回起點,繼續走,第二次相遇的點即為起點
代碼展示:
(1)(無環情況)找到環之后,在讓一個鏈表進入set集合,遍歷另一個鏈表,查遍歷到的元素在不在set中,第一個在的即為起點。
(無環情況)或者先讓兩個鏈表都走,得到兩個鏈表的長度,先看最后一個是不是一樣的,因為相交的話一定有各個部分,然后再讓長鏈表先向前走長的長度減去短的長度即長度的差值,再然后一起走看什么時候兩個節點一樣,第一個一樣的一定會是初始相交的節點
代碼展示:
(2)如果一個有環,另一個無環則不可能相交
(3) 兩個鏈表都有環
有這三種情況,第一種為不相交,第二種為入環節點為同一個,第三種為入環節點不為同一個
第二種情況:先判斷入環節點的地址是否相同,相同的話把入環節點當作終點,接著就可以進行無環情況的操作
區分第一種和第三種:
讓第二個入環點往下走,如果它在回來之前能碰到第一個入環點,則為第三種情況,否則為第一種情況。如果為第一種情況,則返回null,如果為第三種情況。則返回loop1(第一個入環點)或者loop2(第二個入環點)
代碼展示:
主方法:
6、
1、將要刪節點的下一個節點蓋到要刪的節點上,再指向原節點的后一個節點(不好的操作)
2、錯誤示例
最后只是改變了c的指向,但是內存中的指向仍然不變,所以操作是有問題的
答案:是不行的,要刪除節點,必須得給我頭節點才行。
二叉樹的基本算法
1、結構定義:
2、先序,中序,后序遍歷
先序代碼展示:
中序代碼展示:
后序代碼展示:
遞歸序:每一個結點都會到達三次,按先序把到達結點排序出來
先序就是第一次到達的時候就打印
中序就是第二次到達的時候就打印
后序就是第三次到達的時候就打印
他們都是遞歸序加工的結果
3、遞歸實現遍歷
4、非遞歸實現遍歷
先序:壓棧方法:
(1)彈出就打印
(2)如有右孩子就壓入右
(3)如有左就壓左
后序:先序的逆序打印就是后序
中序:
1、整條左邊界依次壓入棧
2、1)無法繼續,就彈出并打印,進入彈出結點的右子樹,繼續1)操作
一個棧實現后序遍歷:
第一個邏輯分支:當我左樹沒處理的情況下處理左樹
第二個邏輯分支:在左樹完成之后再處理右樹
第三個邏輯分支:左右都處理完后,處理自己
5、按層遍歷
代碼展示:
6、找到樹中哪一層最寬:
(1):在結點進隊列的時候就記住它的層數
(2)不用map的方法,只用一個隊列
7、二叉樹的序列化與反序列化:
先序序列化:不要忽略空
代碼展示:
先序反序列化:按先序建,遇空不往下走,走另一邊
代碼展示:
按層序列化:
代碼展示:
孩子為空,就只序列化不加隊列,不為空就即加隊列。又序列化
反序列化:
代碼展示:
8、
最終效果:
代碼展示:
9、
后繼節點:二叉樹的中序遍歷中后一位的節點
題解1:從該節點找到頭節點,再進行中序遍歷找到后繼節點
題解2:
代碼展示:
10、
打印的就是這顆樹的中序遍歷
代碼展示:
二叉樹的遞歸套路
1、
代碼展示:
2、
第一種情況:不經過X,就是左樹和右樹中最大的那顆樹
第二種情況:經過X,就是離左邊最遠到離右邊最遠,即左樹的高度+1+右樹的高度
代碼展示:
3、
二叉搜索樹:左樹值比我小,右樹值比我大,每顆子樹都如此
代碼展示:
4、
代碼展示:
5、
6、
代碼展示:
7、
代碼展示:
8、
方法1:
先將所有父節點存到哈希表里,然后遍歷其中一個節點的父節點,完成后再遍歷另一個節點的父節點,直到第一次遇到相同的父節點,返回
方法2:
代碼展示:
貪心算法(不全)
定義
1、
全排列代碼(暴力解使用):
方法2:
并查集(不全)
圖的算法
推薦圖結構:
轉換代碼:
常見表達方法:
1、
寬度優先:
深度優先:
拓撲排序:
找入度為零的邊通過消邊實現拓撲排序
代碼展示:
最小生成樹:
克魯斯卡爾算法(需要并查集):
代碼展示:
普瑞姆算法(不需要并查集):
代碼展示:
迪杰斯特拉算法:
方法2(使用堆來實現):
暴力遞歸
1、
(1)漢諾塔問題:
方法一(復雜,騰路創新):
方法2(精簡):
2、
2、打印一個字符串的全部子序列:
3、打印一個字符串的全部子序列,要求不要出現重復字面值的子序列:
4、打印一個字符串的全部排列:
5、打印一個字符串的全部排列,要求不要出現重復的排列:(分支限界)
6、
7、
方法1:
方法2、
8、
暴力遞歸到動態規劃
1、
方法1、
方法2、
提取二進制中最右側的1:a&(~a+1)
方法1、
總結
- 上一篇: Collection和Collectio
- 下一篇: 安全算法—SHA-256算法