數據結構與算法應該算是一個比較難的模塊,從小白一路走過來,從大一連續刷過好幾年題,看過挺多書,踩過挺多坑,也漲了一些經驗,姑且在這裏分析一波對數據結構與算法 的學習經驗,請耐心看完,相信對你會有所幫助。android
對於初學者來講,我認爲選擇一本合適、不錯的算法書是很是很是重要的,從大一到如今我也看過很多的算法書,固然在學習算法的過程當中也走過很多坑,刷了不多題,總結了很多經驗,下面說說
個人一些經驗吧,請耐心看完,相信必定對你有所幫助。面試
數據結構與算法相關的書籍應該是我看的最多的一種數據吧,從大一到如今,從未間斷過,下面就介紹下從大一到如今都看過哪些自認爲優秀的書籍,注意,我不知道適不適合你,但我以爲看的過程當中很舒服。算法
一、數據結構與算法分析(c 語言描述版)編程
我相信大部分人大學看的教程都是清華大學出版社嚴蔚敏寫的那本書,說實話,做爲初學者,那本書我沒能堅持看下去,可能比較適合大佬看吧。我本身買了一本《數據結構與算法分析(c 語言描述版)》,挺薄的,不過感受很棒,這本書讓我學到了不少,我的感受也挺容易懂的,代碼實現是採用 C 語言來實現的,不是僞代碼,若是你想學習數據結構,我以爲這本書是個不錯的選擇。班級裏有挺多人看了《大話數據結構》,挺他們說也挺不錯,不過我沒看過。數組
二、挑戰程序設計競賽session
這邊書也是大一時看的,學習算法,刷一些題是必須的,所謂3分理論7分實踐。若是你想刷題,我挺推薦這本書,裏面分初級、中級到高級。雖然每道題沒有講的特別詳細,但當時都看懂了,真心不錯。不太高級那部分我是沒看,初級和中級看着挺舒服。也是學到挺多的,推薦給你們。數據結構
三、算法(第四版)函數
這本書估計是賣的最火的一本書吧,採用 Java 語言來實現的,不過在看這本書以前,我以爲你得要有必定的算法基礎,例如你得知道啥是隊列,啥是棧。我不認爲這是本入門書籍,因此,你能夠先學習
我上門推薦的那些書,有必定的基礎以後,再來學習這本。這本書主要是用大量的圖片來演示算法,讓人以爲比較友好。工具
四、編程之美學習
不用說,很美,這本書是我今年剛入手看的,只能用強烈推薦來形容,在這本書裏,學到了挺多技巧,裏面列舉的題也不是特別難,目前看了 80%,真香。剛開始我聽別人說若是要準備面試谷歌什麼的建議看,我覺得很難,遲遲沒買來看,不過,我看的過程當中,感受還好,相信你也能看的懂,想學習算法、刷題的,強烈推薦。
五、編程珠璣
這本老早就聽別人說過了,去年看的,不過也是看了80%左右,和編程之美同樣,強烈推薦,這本書裏的題,說實話,感受比編程之美有意思,
固然,數據結構與算法的還有不少優秀的書籍,我本身也看過很多,不過以上這些,我以爲很不錯。本身也買過算法導論等,不過,沒看的下去。
這些我也都準備了電子書籍,
不過我發現放百度連接容易失效,若是你感興趣的話,或許能夠關注個人公衆號:苦逼的碼農,回覆「電子書」獲取。
做爲初學者,學習算法是一個相對比較艱難的過程,比起看書,可能看視頻會相對好理解點,固然,這裏引人而異,有些人喜歡看書不喜歡看視頻,這裏主要是根據你自身來選擇了。
提及視頻,我本身看的也很少,我是屬於喜歡看書的那一種,不過我以爲這些這些視頻還不錯,推薦給你們。
一、牛客網有個初級和進階班的視頻,我以爲很不錯,不過我看過進階班的,初級班的沒看過,感受還不錯,截圖以下:
二、直通bat班:這個我以爲也不錯,也是適合新手入門的那種
這些視頻我都有保存在個人百度雲盤,不過可能涉及的版權問題,一會兒就連接失效,因此就不直接貼地址了,感興趣的能夠在個人公衆號:苦逼的碼農,回覆「數據結構與算法」
來獲取。
固然,而已很是歡迎你們關注個人公衆號,個人公衆號主要寫算法、計算機基礎、Java等相關文章,已經有 100 多篇原創文章了,總結了不少與算法相關的技巧。好多文章被各大公衆號轉載。
上面只是介紹了一些書籍和視頻,從另外一個角度講,書籍和視頻只是一個工具,從大一學習算法到如今,刷了不少題,也是積累了一些經驗,下面跟你們分享下個人經驗吧,請耐心看完,相信你會有所收穫
說實話,想要提升本身的算法,我以爲就是腳踏實地着多動手去刷題,多刷題。
可是,若是你是小白,也就是說,你連常見的數據結構,如鏈表、樹以及常見的算法思想,如遞歸、枚舉、動態規劃這些都沒學過,那麼,我不建議你盲目瘋狂着去刷題的。而是先去找本書先去學習這些必要的知識,而後再去刷題。
由於,若是這些基礎都不懂的話,估計一道題作了幾個小時,而後看答案都不不懂,作題沒有任何思路,這是很難受的。長此以往,估計沒啥動力了,我剛開始就是這樣,一道題答案看一天,然而仍是不大懂,什麼回溯啊,暴力啊,還不知道是啥意思。
也就是說,假如你要去諸如leetcode這些網站刷題,那麼,你要先具有必定的基礎,這些基礎包括:
一、常見數據結構:鏈表、樹(如二叉樹)。(是的,鏈表和二叉樹是重點,圖這些能夠先放着)
二、常見算法思想:貪婪法、分治法、窮舉法、動態規劃,回溯法。(貪婪、窮舉、分治是基礎,動態規劃有難度,能夠先放着)
以上列出來的算是最基本的吧。就是說你刷題以前,要把這些過一遍再去刷題。若是你連這些最基本的都不知道的話,那麼你再刷題的過程當中,會很難受的,思路也會相對比較少。
總之,千萬不要急,先把這些基本的過一遍,力求理解,再去刷題。這些知識點,我上面已經給大家推薦了對應的書籍和視頻了,就不繼續說了。
因此大家千萬別期望覺得本身把這些思想學完以後刷題會很牛,只有多刷題,只有多動手實踐,你的靈敏度纔會提升起來。
總結下:
提升數據結構與算法沒啥捷徑,最好的捷徑就是多刷題。可是,刷題的前提是你要先學會一些基本的數據結構與算法思想。
如何刷題?如何對待一道算法題?
我以爲,在作題的時候,必定要追求完美,千萬不要把一道題作出來以後,提交經過,而後就趕忙下一道。我認爲這意義不大,由於一道題的解法太多了,有些解法態粗糙了,咱們應該要尋找最優的方法。
算法能力的提高和作題的數量是有必定的關係,但並非線性關係。也就是說,在作題的時候,要力求一題多解,若是本身實在想不出來其餘辦法了,能夠去看看別人是怎麼作的,千萬不要以爲模仿別人的作法是件丟人的事。
我作題的時候,我一看到一道題,可能第一想法就是用很粗糙的方式作,由於不少題採用暴力法都會很容易作,就是時間複雜度很高。以後,我就會慢慢思考,看看有沒其餘方法來下降時間複雜度或空間複雜度。最後,我會去看一下別人的作法,固然,並非每道題都會這樣執行。
衡量一道算法題的好壞無非就是時間複雜度和空間複雜度,因此咱們要力求完美,就要把這兩個降到最低,令他們相輔相成。
我舉道例題吧:
問題: 一隻青蛙一次能夠跳上1級臺階,也能夠跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法?
這道題我在之前的分章分析過,不懂的能夠先看下以前寫的:遞歸與動態規劃---基礎篇1
方法1::暴力遞歸
這道題不難,或許你會採起下面的作法:
public static int solve(int n){ if(n == 1 || n == 2){ return n; }else if(n <= 0){ return 0; }else{ return solve(n-1) + solve(n-2); } }
這種作法的時間複雜度很高,指數級別了。可是若是你提交以後僥倖經過了,而後你就接着下一道題了,那麼你就要好好想一想了。
方法二:空間換時間
力求完美,咱們能夠考慮用空間換時間:這道題如何你去仔細想想,會發現有不少是重複執行了。因此能夠採起下面的方法:
//用一個HashMap來保存已經計算過的狀態 static Map<Integer,Integer> map = new HashMap(); public static int solve(int n){ if(n <= 0)return 0; else if(n <= 2){ return n; }else{//是否計算過 if(map.containsKey(n)){ return map.get(n); }else{ int m = solve(n-1) + solve(n-2); map.put(n, m); return m; } } }
這樣,能夠大大縮短期。也就是說,當一道題你作了以後,發現時間複雜度很高,那麼能夠考慮下,是否有更好的方法,是否能夠用空間換時間。
方法三:斐波那契數列
實際上,咱們能夠把空間複雜度弄的更小,不須要HashMap來保存狀態:
public static int solve(int n){ if(n <= 0) return 0; if(n <= 2){ return n; } int f1 = 0; int f2 = 1; int sum = 0; for(int i = 1; i<= n; i++){ sum = f1 + f2; f1 = f2; f2 = sum; } return sum; }
我弄這道題給大家看,並非在教大家這道題怎麼作,而是有如下目的:
一、在刷題的時候,咱們要力求完美。
二、我想不到這些方法啊,怎麼辦?那麼你就能夠去看別人的作法,以後,遇到相似的題,你就會更有思路,更知道往哪一個方向想。
三、能夠從簡單暴力入手作一道題,在考慮空間與時間之間的衡量,一點點去優化。
什麼叫溫馨區?在刷題的時候,可能有一類題是你比較懂的,你每次一看就有思路,而後半個小時就擼好代碼,提交代碼,而後經過了,而後,哇,又多刷了一道題,內心很舒服。
可是,記住,前期你能夠多刷這種題練手,提高本身的樂趣,但,我仍是建議你慢慢跳出溫馨區,去作一些本身不擅長的題,而且找段時間一直刷這種題。例如,我以爲我在遞歸方面的題仍是挺強的,
可是,我對動態規劃的題,很菜,每次都要想很久,每次遇到這種題都有點懼怕,沒什麼信心。不過有段時間我以爲只刷動態規劃的題,直接在 leetcode 選定專題,連續作了七八十道,剛開始很難受,
後來就慢慢知道了套路了,一道題從兩三個小時最後縮到半小時,簡單的十幾分鍾就搞定。感受本身對這類型的題也不害怕的。
因此,建議你,必定要學好跳出本身的溫馨區。
我通常是在leetcode和牛客網刷題,感受挺不錯,題目難度不是很大。
在牛客網那裏,我主要刷劍指Offer,不過那裏也有個在線刷leetcode,不過裏面的題量比較少。牛客網刷題有個很是方便的地方就是有個討論區,那裏會有不少大佬分享他們的解題方法,不用咱們去百度找題解。因此你作完後,實在想不出,能夠很方便着去看別人是怎麼作的。
至於leetcode,也是大部分題目官方都有給出答案,也是個不錯的刷題網站。大家能夠兩個挑選一個,或者兩個都刷。
固然,還有其餘刷題的網站,不過,其餘網站沒刷過,不大清除如何。
至於leetcode,有中文版和英文版,我的建議英文版,英文版裏面有各類大佬的解法分析。
leetcode有中文版
根據本身的興趣選。
說實話,有些題在你沒看別人的解法前,你好不知道有這麼美妙優雅的解法,看了以後,臥槽,竟然還能夠這樣。而咱們在刷題的過程當中,就要不斷累積這些技巧,當你累計多了,你就會造成一種
神經反應,一會兒就想到了某種方法。解題技巧不少,例如數組下標法、位圖法、雙指針等等,我本身也分享過一篇總結一些算法技巧的文章。給你舉個例子吧,有時候有些技巧真讓你大喊「臥槽」。
給你一組整型數據,這些數據中,其中有一個數只出現了一次,其餘的數都出現了兩次,讓你來找出一個數 。
這道題可能不少人會用一個哈希表來存儲,每次存儲的時候,記錄 某個數出現的次數,最後再遍歷哈希表,看看哪一個數只出現了一次。這種方法的時間複雜度爲 O(n),空間複雜度也爲 O(n)了。
然而我想告訴你的是,採用位運算來作,絕對高逼格!
咱們剛纔說過,兩個相同的數異或的結果是 0,一個數和 0 異或的結果是它自己,因此咱們把這一組整型所有異或一下,例如這組數據是:1, 2, 3, 4, 5, 1, 2, 3, 4。其中 5 只出現了一次,其餘都出現了兩次,把他們所有異或一下,結果以下:
因爲異或支持交換律和結合律,因此:
1^2^3^4^5^1^2^3^4 = (1^1)^(2^2)^(3^3)^(4^4)^5= 0^0^0^0^5 = 5。
也就是說,那些出現了兩次的數異或以後會變成0,那個出現一次的數,和 0 異或以後就等於它自己。就問這個解法牛不牛逼?因此代碼以下
int find(int[] arr){ int tmp = arr[0]; for(int i = 1;i < arr.length; i++){ tmp = tmp ^ arr[i]; } return tmp; }
時間複雜度爲 O(n),空間複雜度爲 O(1),並且看起來很牛逼。
若是讓你求解 2 的 n 次方,而且不能使用系統自帶的 pow 函數,你會怎麼作呢?這還不簡單,連續讓 n 個 m 相乘就好了,代碼以下:
int pow(int n){ int tmp = 1; for(int i = 1; i <= n; i++) { tmp = tmp * m; } return tmp; }
不過你要是這樣作的話,我只能呵呵,時間複雜度爲 O(n) 了,怕是小學生都會!若是讓你用位運算來作,你會怎麼作呢?
我舉個例子吧,例如 n = 13,則 n 的二進制表示爲 1101, 那麼 m 的 13 次方能夠拆解爲:
m^1101 = m^0001 * m^0100 * m^1000。
咱們能夠經過 & 1和 >>1 來逐位讀取 1101,爲1時將該位表明的乘數累乘到最終結果。直接看代碼吧,反而容易理解:
int pow(int n){ int sum = 1; int tmp = m; while(n != 0){ if(n & 1 == 1){ sum *= tmp; } tmp *= tmp; n = n >> 1; } return sum; }
時間複雜度近爲 O(logn),並且看起來很牛逼。
給你算法技巧,固然也能夠關注個人公衆號:苦逼的碼農,專一與分享算法、計算機基礎等相關文章,已有100多篇原創,歡迎來撩。
推薦閱讀:一些經常使用的算法技巧總結
例如在刷題的時候,咱們要學會巧用雙指針、數組下標法、位運算等等技巧來解決問題,可能會有意想不到的效果。我給你再找點我以前寫文章的一些例子吧:
這是個長期累積的過程,我本身也精彩在個人公衆號裏分享一些解題的文章,感興趣的能夠關注個人公衆號:苦逼的碼農。
前面我主要是說了我平時都是怎麼學習算法的。在數據結構方法,我只是列舉了大家必定要學習鏈表和樹(二叉堆),但這是最基本的,刷題以前要掌握的,對於數據結構,我列舉下一些比較重要的:
一、鏈表(如單向鏈表、雙向鏈表)。
二、樹(如二叉樹、平衡樹、紅黑樹)。
三、圖(如最短路徑的幾種算法)。
四、隊列、棧、矩陣。
對於這些,本身必定要動手實現一遍。你能夠看書,也能夠看視頻,新手能夠先看視頻,不過前期能夠看視頻,以後我建議是必定要看書。
例如對於平衡樹,可能你跟着書本的代碼實現以後,過陣子你就忘記,不過這沒關係,雖然你忘記了,可是若是你以前用代碼實現過,理解過,那麼當你再次看到的時候,會很快就記起來,很快就知道思路,並且你的抽象能力等等會在不知不覺中提高起來。以後再學習紅黑樹啊,什麼數據結構啊,都會學的很快。
動手去作,動手去作,動手去作。重要的話說三遍。
千萬不要找了一堆資源,訂好了學習計劃,我要留到某某天就來去作.....
千萬不要這樣,而是當你激情來的時候,就立刻去幹,千萬不要留到某個放假日啊什麼鬼了,不少這種想法的人,最後會啥也沒作的。
也不要以爲要學習的有好多啊,不知道從哪學習起。我上面說了,能夠先學習最基本的,而後刷題,刷題是一個須要長期堅持的事情,一年,兩年。在刷題的過程當中,能夠穿插和學習其餘數據結構。
你們也能夠關注個人公衆號:苦逼的碼農,在個人公衆號裏,我也分享了不少與數據結構算法相同的文章,並且也分享了不少解題技巧。目前已分析了 100 多篇原創文章,下面是一些我以爲
很不錯的文章,強烈建議閱讀:
鏈表的重要性不言而喻,若是你把我分享的這10道題都搞懂了,那麼你在鏈表方面算過關的了:
就不一道道列出來了,一共挑選了10還不錯的文章
我還講解了一些經常使用數據結構與算法思想,每篇都通俗易懂着講解了,被各類號所轉發
二、十大排序重要性不言而喻,文章還附帶了動畫、講解文章,代碼
必學十大經典排序算法,看這篇就夠了(附完整代碼/動圖/優質文章)(修訂版)
三、總結了刷題過程當中經常使用的技巧,推薦閱讀:一些經常使用的算法技巧總結
四、用漫畫的形式講解了AVL樹:【漫畫】之後在有面試官問你AVL樹,你就把這篇文章扔給他。
五、大量圖講解了堆的各類操做:【算法與數據結構】堆排序是什麼鬼?
索性把寫的一些文章連接都分享一波,你們能夠挑感興趣的看算法與數據結構系列文章
也很是歡迎你們關注公衆號「苦逼的碼農」裏面已有100多篇原創文章,我也分享了不少視頻、書籍的資源,以及開發工具,歡迎各位的關注,第一時間閱讀個人文章。
若是你以爲這篇內容對你挺有啓發,我想邀請你幫我三個忙,讓更多的人看到這篇文章:
一、點贊,讓更多的人也能看到這篇內容(收藏不點贊,都是耍流氓 -_-)
二、關注我和專欄,讓咱們成爲長期關係
三、關注公衆號「苦逼的碼農」,主要寫算法、計算機基礎之類的文章,裏面已有100多篇原創文章
大部分的數據結構與算法文章被各類公衆號轉載相信必定能讓你有所收穫
我也分享了不少視頻、書籍的資源,以及開發工具,歡迎各位的關注個人公衆號:苦逼的碼農,每週推送幾篇原創文章,相信 會讓你有所收穫。