目录
完結了,整整六十幾天基本上每天不是在刷題就是在刷題的路上
要說我最大的感想是甚麼,那就是第一次如此完整的刷題,對於算法的知識點也有了一次總體性的瞭解。
也利用這次機會學習了c++,也認知到自己有哪些地方仍不熟悉。
但長路漫漫仍需砥礪前行,這第一刷只是讓我對於刷題會用到的工具有了初步的認識,但我不認為我目前可以熟練地使用這些工具,比如說KMP算法、二叉數、回溯算法、01背包等等等這些解題思路只能說我有印象,但實際要使用仍需要不斷的去使用去熟練,
如果你正在刷題或者是刷題前要看一下前人的心得,我想告訴你
💡 長路漫漫,你我一起砥礪前行,加油!
使用雜湊表的目的就是可以快速判斷一個元素是否存在在集合裡
至於雜湊表中的雜湊函數與碰撞的處理,我在之前的這篇文章中就有做詳細介紹了,就不多做贅述。
主要針對雜湊表三個常見的數據結構來做總結
在數據量比較小的狀態下,我可以使用數組來實現hashtable 而裡面的hashfunction我可以自己設計,就像是有效的字母异位词 可以用"-'a'" (類似hashfunction)來找到對應的hashvalue,並存入count值
在使用set的狀況下,跟數組狀況很像,但數據量太大,使用array會佔用太多內存空間 所以使用set,在unordered_set中,底層會對數值進行hash運算後,找出對應的下標存入我們的值(?這裡我搞不太 懂set的底層邏輯),因為數值不能重複,類似於數組中我們不存count,是固定存"1"
在使用map的狀況,主要是因為我們需要對兩個值進行索引 所以在使用在unordered_map中,使用狀況是,需要進行key-value的對應,可以設定key值是多少,map會對key值進行hash計算,得出hashvalue,並存入key的對應value到hashvalue的位置,
在字符串的學習當中,因為之前都是碰C,所以對於C++的庫函數都很不熟悉,比如最基礎的swap以及reverse都不太熟悉,但是正因為這個事情,所以我比較少去依賴庫函數,常常會想自己做,不過這個過程中,也是真的很有趣,比如說反轉字串,我學到了還可以用位運算進行字串反轉,真的是驚到我了
在學習反轉字串的時候,雙指針法真的很好用,其實廣義來說KMP也是用到兩個指針,來進行變換,讓我了解到,不是有越多工具越好,有時可以把一項精典工具用精,就可以很容易的去處理
在反轉字符串ll 以及翻轉字符串的單詞,以及左旋轉字符串,都讓我感到很好玩,原來程式可以這麼花式,並且我在跟其他群組的小夥伴討論左旋轉字符串時,我還了解到這個如果要深究還可以牽涉到某個數論,真的非常有趣
我不敢說我自己已經了解了,在學習KMP的過程當中,其實碰到很多困難,但就是靜下心來去畫圖,重複看好幾片影片以及小夥伴提供的資料去輔助,我感覺到後面寫起來是知道為甚麼這一段CODE要這麼寫,而不是照著模板,這樣的學習真的很讓人滿足
字符串就像卡哥說的,想法很簡單,但實現起來其實有很多眉眉角角要進行處理,雙指針法好好用,KMP法要想辦法更加了解其精隨,學習字符串的過程中,感覺到最多的不是困難,而是有趣,尤其是自己想盡辦法思考出來的思路,假設有一點點跟提解接近,那就會很開心了。
先進後出,想像羽球桶,最先放進去的最後拿到
在處理Stack的問題時,常常會感覺就是在玩對對碰,只是每次的對對碰規則都有一點點差異比如說
玩起來都蠻有趣的,並且在卡哥的總結也有提到linux系統當中”cd”這個command也是一個stack經典應用
還有當我們遇到系統崩潰時,stack也會依序pop出系統資訊協助我們debug,stack真的隱身在我們的身邊當中
先進先出,想嚇成珍珠奶茶的大吸管,先進到吸管的珍珠一定先進入嘴巴
Stack 跟 Queue 在C++的學習當中,終於有點窺見這個資料結構的好玩之處,之前因為都使用C,所以需要對於各種結構自己手做,抗性就比較大,但C++可以讓我先抽離最底層,從上層的視角去對這兩個資料結構進行操作,操作完真的感覺很有趣,思考的過程也被多次啟發
在二叉樹章節當中,我不敢說自己完全清晰了,但對於之前的我來說,已經是個巨大的進步,之前看到二叉樹只在前中後序遍歷就停下腳步了,沒有想過自己可以把這個部分完整的跑過一次,對於二叉樹的概念也有比較清晰的感覺了,只是接下來還是要對一些項目進行釐清
回溯算法整體做完後,其實在做的過程中基本上都離不開回溯法的模板,大致都大同小異
其實更多的是對於資料結構的考察熟悉程度,以及如何去看到問題的狀態。
最後想像遞迴的過程中如何嵌套循環與如何想像這個樹形結構長甚麼模樣。
- void backtracking(參數) {
- if (終止條件) {
- 存放結果;
- return;
- }
-
- for(選擇: 本層有多少元素){
- 處理節點;
- backtracking(路徑,選擇列表) \\\\遞迴
- 回溯,撤銷處理結果
- }
- return;
- }
對於回溯的算法,有幾個卡哥提到的回溯算法的本質問題
有些問題卡在自己對於C++的數據結構不熟悉,有些題目卡在觀念不熟悉,但在一刷時可以完整地做完這些題目,很明顯感覺到自己的思考更加清晰了。
回顧貪心算法,真的沒有固定的解法,可能有類似的套路,比如說重疊區間,或者是子序和,但整體還是一個思路上的轉換
貪心算法很簡單,主要體現在代碼上,但難點主要是思路上的轉換,說簡單也不簡單
沒有套路!沒有套路!沒有套路
真的是要讓自己的視野打開,多寫多練習,讓自己的腦袋瘋狂運轉,會越來越好的
其實任何情況下只要能推導出局部最優在堆疊到全局最優的題目都可以是貪心算法,但有些問題當然可以套用其他的解題技巧幫忙,貪心算法我認為就像是心法,它沒有招式但所以我們只能意會,很奇妙的章節。
定義DP數組以及下標的含意
如果想不清楚dp数组的具体含义,递归公式从何谈起,甚至初始化的时候就写错了。
dp[i][j] i 代表甚麼意思,j代表甚麼意思
dp[i] i 代表甚麼意思,元素代表甚麼意思
遞推公式
根據遞推公式,確定DP數組如何初始化
例如**动态规划:不同路径还不够,要有障碍! (opens new window)**在这道题目中,初始化才是重头戏
確定遍歷順序
如果看过背包系列,特别是完全背包,那么两层for循环先后顺序绝对可以搞懵很多人,反而递归公式是简单的。
打印dp數組
至于推导dp数组的重要性,动规专题里几乎每篇Carl都反复强调,当程序结果不对的时候,一定要自己推导公式,看看和程序打印的日志是否一样。
遞推公式不該是過於關注的點,它只是解題的一部分,別讓自己在解題時處於黑盒狀態
動態規劃每一個狀態一定是由上一個狀態推導出來,而貪心則是從局部選最優堆疊成全局最優
單調棧,就是當要尋找一個元素左邊或者右邊第一個比自己大的元素位置,就可以考慮使用單調棧。
其本質是使用空間換時間,在遍歷的過程中使用棧來記錄右邊比當前元素高或低,優點就是数組只需要遍歷一次
使用單調棧時需要明確