leetcode刷題心得

本人以前大概搞過半年的算法,不是什麼大佬,學得也不怎麼樣,一般般。leetcode只刷了200左右(沒有水題),leetcode簡單、中等級別的題目大部分都可以做。大部分公司的筆試題也還行,當然了像字節、騰訊那種就太難了,根本頂不住,面試遇到的算法題一般也能答得上來(其實也沒啥面大廠的機會),偶爾也會有失誤。

先說一說刷leetcode的前提,建議不要完全零基礎就一股腦的去刷題,如果你啥都不會臨時突擊直接上去刷題的話emmmm,不出意外的話你只會看着別人的題解刷題,看了別人的思路你也不一定會寫,就算寫出來了很快你就忘了。所以要對常見的算法有一定的基礎,常見的模型較爲了解之後再去刷題。比如常見排序(冒泡、快排、插入、堆排、歸併…)、雙指針(快慢指針、左右指針)、貪心二分(二分查找)、搜索(dfs、bfs、各種剪枝、回溯思想)、動態規劃(各種子序列、各種子串、常見的那幾個揹包問題)、前綴和的常見操作(各種遍歷、各種樹的性質、最小生成樹)、(最短路、常見性質)、常見數據結構和集合類(鏈表、隊列、棧、map、list、set、並查集都得會用),這些基礎知識不求你精通,不會寫代碼都行,但是你總得知道這些知識咋回事。當然瞭如果你是搞過acm競賽之類的大神,這些可以都跳過,直接上手。關於怎麼學習這些基礎的算法知識,個人建議新手看視頻或者看帶圖的博客,看博客文字的話可能看不懂,直接就勸退了,當然有點算法底子之後直接看博客也是沒問題的。

那麼該刷leetcode的哪些題,截止到目前爲止leetcode已經有1300+的題目了,其實不用全部都去刷(對大部分人來說也沒那個時間),刷那些比較熱門的就ok,或者按照各個知識點去刷。所有的題目分簡單、中等困難三個等級,根據我個人的經驗來看,簡單和中等的題目出現的頻率是最高的,困難級別的很少見,所以建議刷題數量中等>簡單>困難。關鍵是困難的太難了,一道題目可能兩三天你都還搞不出來,一來怕把你勸退了,二來性價比不高,所以困難的刷一小部分就好了。有一些很簡單沒有用到任何算法的模擬題、博弈論、最大流、特別複雜的樹和圖操作,一般來說這些知識筆試面試都不會考。so刷題具體要怎麼刷呢,看完題目之後不要直接看別人的題解,先自己思考,正常情況下很少會馬上就想到最優的解法,要從暴力、爆搜開始思考,然後再進一步思考怎麼去優化複雜度。常見的思考方向如下:

  • 常見的枚舉可以看一看枚舉的範圍是否有序,可以考慮用二分;
  • 雙重循環看一看是否可以用雙指針;
  • 一些要查找的O(n)複雜度的部分是否可以用map、set;
  • 括號、迴文之類可以思考一下能否用棧;
  • 一些暴力搜索的部分看一看是否存在根本不可能到達的狀態可以考慮剪枝;
  • 暴力搜索時看看是否有可重複利用的狀態用map或數組把狀態存起來(記憶化搜索),然後再看看是否可以用動態規劃;
  • 一些枚舉的範圍很大一看就知道不可能ac可能思考一下是否可以直接推出結論或數學公式(貪心的思考方向);
  • 一些感覺是動態規劃的題目貌似,貌似每一個狀態都是有規律的可以嘗試用打表這種比較賴皮的方法;
  • 一些需要反覆計算的部分如果是固定的,可以考慮先計算好然後把它存起來,下次直接拿來用(前綴和思想);
  • 一些題目的條件和經典題型很像的可以考慮直接套用經典題型(例如01揹包模型,完全揹包模型);
  • 一些常見的操作可以看看有沒有現成的類或方法可以直接拿來用(例如java大數、排序、字符串反轉、拼接等常見操作);
  • 一些數字的操作可以看看是否涉及到二進制,可以嘗試下異或、&這些操作;
  • 動態規劃的題目看一看這一次的狀態和上一步的狀態是否離得很近,如果離得很近可以考慮狀態壓縮,降低空間複雜度(例如斐波那契,每一次的狀態只和前面兩步狀態有關);
  • 如果題目給出了樣例範圍可以先通過樣例範圍反推出算法的時間複雜度,從而考慮題目大概可以用什麼算法。

我的表達能力不太好,可能上面的描述的思考方向有點不太好理解,也是我個人的總結,如果有不對的地方,請多多指正。順帶說一下,leetcode上面的題目的測試樣例並不是特別完善,有一些題目樣例偏小,用暴力做也是可以ac的,所以千萬不要因爲單純的ac去刷題,我看到一些用暴力ac了題目在評論區炫耀的,還引以爲榮喊着ac了就行,emmmm自己體會吧。做完題目之後怎麼去利用題解?很多題目是不止一種最優解的,會存在多種最優解,上面已經說過了,不要爲了ac去刷題,爭取要把多種解法都搞明白(儘量看那種熱度高的、帶圖的)。看完他們的思路、最優解法之後,要思考最初的暴力法是怎麼過渡到最優解法的,不要只是單純的把這道題目的最優解法背下來,毫無意義。暴力法 ----> 最優解法,中間的這個過渡過程纔是最重要的,這樣學才能體會到學算法的快落,就像學數學一樣,記住這個公式沒有什麼用,要知道這個公式是怎麼從已知條件推出來的,這纔是最重要的。

最後解答下一些常見的疑問。

Q:爲了筆試面試什麼時候準備算法比較好?
A:越早越好,因爲算法不同於其他的知識,數據庫、語言基礎這些東西臨時突擊再不濟也能背一點下來。可是算法是不能突擊的,你早一點準備的話,在面試高峯期的時候就可以把時間放在複習其他知識上面了。從筆試情況來看,大部分公司基本上都是必考編程題。所以越早準備越好。

Q:用什麼語言寫算法代碼比較好?
A:習慣了用什麼語言就用什麼語言,語言只是工具,用啥都行,不過能用c++就儘量用c++吧,因爲大部分題解用的都是c++。像java之類的太依賴快捷鍵了,一些筆試不能用本地ide,沒有快捷鍵連個包都導不出來,而且有一些宣講會是現場筆試的,手寫代碼非常影響心情和速度,平時有事沒事可以多去練練手寫代碼。

Q:題目讀不懂怎麼辦?
A:其實專門針對筆試面試的話題目讀不懂這種情況還是比較少的,那些搞競賽的遇上壓軸題題目讀不懂很正常,筆試面試一般都是單刀直入。筆試可以結合樣例仔細地多讀幾遍題目,慢慢的摳字眼,一般都能讀懂。面試的話有時候是面試官描述得不太好,可以去問面試官,讓他說得再詳細一點,讓他多給個樣例,讓他舉個例子,然後你再把你的理解和麪試官說一下再次確認。切記題目沒完全搞明白就直接下手寫代碼,這就和開發需求還沒搞明白就開始code是一樣的。

Q:讀完題目之後一點思路都沒有怎麼辦
A:先把最簡單最直接的暴力做法想出來,然後再慢慢的去優化,參考上面的思考方向。要知道除了大神,很多題目都不會讓你一眼就看到最優的解法,都是慢慢思考出來的,這個從暴力法到最優解法的思考過程纔是算法的樂趣。就算你想不到最優的解法,能優化一點是一點,很多公司的判分就是看你能過多少樣例。面試也是同樣的道理,先說出暴力法,然後慢慢過渡到最優的解法,體現出這個思考過程,面試官會覺得你有思考深度。換句話說,哪怕這題你不會,你把暴力法說出來,也總比直接放棄跟面試官說不會好啊。

Q:有思路但是代碼寫不出來怎麼辦
A:其實對算法而言,思路纔是最重要的,寫代碼是最後一步,也是最簡單的一步。你可以去問一下身邊搞acm的同學,他會認可這句話的。你要是能把思路說得清清楚楚明明白白,肯定可以把代碼寫下來,寫不出來是因爲平時這類代碼寫得少,沒有去總結。平時要多去看看模板,多去看看大神寫的代碼,像二分法是有模板的;鏈表如果要操作頭部通的話常可以給頭部加個空節點;一些要處理頭尾的數組可以從1開始;二維數組地圖類的題目要遍歷多個方向可以把方向存到數組裏例如int[][] next = {{0,1},{0,-1}…};還有字符串處理、保留n位小數、括號類()的處理、迴文串等等這些代碼都是有模板有技巧的。這樣可以讓你的代碼更加簡短容易讓人讀懂,也不容易出錯。每一次刷題ac完之後都去看看大神的代碼,平時多練習、多總結、多交流。慢慢的你就可以寫出簡單高效不容易出錯的代碼了。

Q:思路是正確的,但是代碼寫出來是錯的怎麼改
A:打斷點debug,認真查看各個變量的變化,一步一步往下點,這個過程就是你的算法思路,如果還是看不出來,就拿草稿紙畫圖,把變量記下來。這個起步是很痛苦的,我剛學dfs的時候調試八皇后的代碼調了一個晚上。

Q:思考的時候總是漏掉一些情況,代碼總是缺斤少兩,不能一次ac怎麼辦
A:其實不光是筆試面試,搞競賽的也是一樣,總是罰時了好多次才能ac。筆試的時候可以馬上評測告訴你通過了多少樣例還好,如果是不馬上告訴你評測結果只讓你提交代碼的話,本來能ac的只能過80%、50%多難受。建議不管是練習還是筆試,每一次提交代碼之前都要想出多種特殊樣例進行多次自測,每一次都告訴自己只有一次機會,同時也要注意樣例範圍和格式,如果是牛客網平臺筆試的話一定要先自測再提交代碼。怎麼想出特殊樣例呢?舉個簡單的例子假如讓你寫一個排序算法,可以自己想出特殊的樣例,例如:[],[3],[6,6,6],[3,4,5],[5,4,3],[1,-1,1,-1],[0,0,0],[min,min,min],[max,max,max],這些都算是特殊樣例,多去測一測,如果代碼有問題很快就可以看出來了。

最後奉獻一下一位大佬的由數據範圍反推算法複雜度以及算法內容的總結

資源來源

一般ACM或者筆試題的時間限制是1秒或2秒。
在這種情況下,C++代碼中的操作次數控制在 107107 爲最佳。
下面給出在不同數據範圍下,代碼的時間複雜度和算法該如何選擇:

n≤30n≤30, 指數級別, dfs+剪枝,狀態壓縮dp
n≤100n≤100 => O(n3)O(n3),floyd,dp
n≤1000n≤1000 => O(n2)O(n2),O(n2logn)O(n2logn),dp,二分
n≤10000n≤10000 => O(n∗n√)O(n∗n),塊狀鏈表
n≤100000n≤100000 => O(nlogn)O(nlogn) => 各種sort,線段樹、樹狀數組、set/map、heap、dijkstra+heap、spfa、求凸包、求半平面交、二分
n≤1000000n≤1000000 => O(n)O(n), 以及常數較小的 O(nlogn)O(nlogn) 算法 => hash、雙指針掃描、kmp、AC自動機,常數比較小的 O(nlogn)O(nlogn) 的做法:sort、樹狀數組、heap、dijkstra、spfa
n≤10000000n≤10000000 => O(n)O(n),雙指針掃描、kmp、AC自動機、線性篩素數
n≤109n≤109 => O(n√)O(n),判斷質數
n≤1018n≤1018 => O(logn)O(logn),最大公約數
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章