相關(guān)推薦:
-----------
我知道各位是被標(biāo)題吸引進(jìn)來的,那就不廢話,先說幾個算法筆試的硬核套路抗果,再說說做題復(fù)習(xí)的策略。
避實就虛
大家也知道潜叛,大部分筆試題目都需要你自己來處理輸入數(shù)據(jù)虹钮,然后讓程序打印輸出翼雀。判題的底層原理是奏黑,把你程序的輸出用 Linux 重定向符 >
寫到文件里面炊邦,然后比較你的輸出和正確答案是否相同。
那么有的問題難點就變得形同虛設(shè)熟史,我們可以偷工減料馁害,舉個簡化的例子,假設(shè)題目說給你輸入一串用空格分隔的字符以故,告訴你這代表一個單鏈表蜗细,請你把這個單鏈表翻轉(zhuǎn)裆操,并且強(qiáng)調(diào)怒详,一定要把輸入的數(shù)字轉(zhuǎn)化成單鏈表之后再翻轉(zhuǎn)哦!
那你怎么做踪区?真就自己定義一個 ListNode
單鏈表節(jié)點類昆烁,然后再寫代碼把輸入轉(zhuǎn)化成一個單鏈表,然后再用讓人頭暈的指針操作去老老實實翻轉(zhuǎn)單鏈表缎岗?
搞清楚我們是來 AC 題目的静尼,不是來學(xué)習(xí)算法思維的。正確的做法是直接把輸入存到數(shù)組里传泊,然后用 雙指針技巧 幾行代碼給它翻轉(zhuǎn)了鼠渺,然后打印出來完事兒。
我就見過不少這種題目眷细,比如題目說輸入的是一個單鏈表拦盹,讓我分組翻轉(zhuǎn)鏈表,而且還特別強(qiáng)調(diào)要用遞歸實現(xiàn)溪椎,就是我們舊文 K 個一組翻轉(zhuǎn)鏈表 的算法普舆。嗯恬口,如果用數(shù)組進(jìn)行翻轉(zhuǎn),兩分鐘就寫出來了沼侣,嘿嘿祖能。
還有我們前文 扁平化嵌套列表 講到的題目,思路很巧妙蛾洛,但是在筆試中遇到時养铸,輸入是一個形如 [1,[4,[6]]]
的字符串,那直接用正則表達(dá)式把數(shù)字抽出來雅潭,就是一個扁平化的列表了……
PS:我認(rèn)真寫了 100 多篇原創(chuàng)揭厚,手把手刷 200 道力扣題目,全部發(fā)布在 labuladong的算法小抄扶供,持續(xù)更新筛圆。建議收藏,按照我的文章順序刷題椿浓,掌握各種算法套路后投再入題海就如魚得水了太援。
巧用隨機(jī)數(shù)
再說一個雞賊的技巧,注意那些輸出為「二值」的題目扳碍,二值就是類似布爾值提岔,或者 0 和 1 這種組合有限的。
比如說很多題目是這樣笋敞,巴拉巴拉給你說一堆條件碱蒙,然后問你輸入的數(shù)據(jù)能不能達(dá)成這些條件,如果能的話請輸出 YES
夯巷,不能的話輸出 NO
赛惩。
如果你會做當(dāng)然好,如果不會做怎么辦趁餐?
首先這樣提交一下:
public class Main {
public static void main(String[] args) {
System.out.println("YES");
}
}
看下 case 通過率喷兼,假設(shè)是 60%,那么說明結(jié)果為 YES
有 60% 的概率后雷,所以可以這樣寫代碼:
public class Main {
public static void main(String[] args) {
// 60% 的概率輸出 YES季惯,40% 的概率輸出 NO
System.out.println((new Random().nextInt() % 100) < 60 ? "YES" : "NO");
}
}
嘿嘿,labuladong 說了臀突,這題你可以不會勉抓,但是一定要在力所能及的范圍內(nèi)做到極致!
概率大師
說一個場景候学,如果筆試出現(xiàn)那種惡心人的單選藕筋,四個選項全都沒見過,然后你蒙了一個 C盒齿。
假設(shè)念逞,過了一會你突然靈光一閃困食,喚起一些零碎的記憶,確定 B 選項是錯的翎承,那么硕盹,這時候你該怎么做?
重新在 A 和 D 中間蒙一個啊哥哥叨咖!不重新蒙瘩例,正確的概率是 1/4,重新蒙甸各,正確的概率是 3/8垛贤,白撿的概率都不要么?
是不是覺得不可思議趣倾?是不是覺得我在胡扯聘惦?
這樣,假設(shè)一道選擇題有 100 個選項儒恋,你隨便蒙一個善绎,正確率為 1%,錯誤率為 99%诫尽。
假設(shè)現(xiàn)在 labuladong 顯靈禀酱,幫你在剩下的 99 個選項中排除了 98 個錯誤選項,只剩下一個選項牧嫉,然后問你剂跟,你繼續(xù)堅持原來的選擇,還是換成幫你排除剩下的那個選項酣藻?
換安芮ⅰ!換了之后正確概率是 1 - 1% = 99% 半怠衣洁!
那如果 labuladong 只幫你排除了 90 個錯誤選項墓捻,剩下 9 個選項抖仅,那你要不要換成這 9 個選項中的某一個?
換白┑凇撤卢!換了之后正確概率是 (1 - 1%) / 9 = 11% 啊梧兼!
那回過來看放吩,四個選項,你開始蒙了一個羽杰,后來靈光一閃在剩下三個選項中排除了一個錯誤答案渡紫,那你換不換到推?
換啊惕澎!換了之后正確概率是 (1 - 1/4) / 2 = 3/8 袄虿狻!
其實這就是典型的「三門問題」唧喉,不知道的話看舊文 幾個反直覺的概率問題捣卤。
編程語言的選擇
僅從做算法題的角度來說,我個人比較建議使用 Java 作為筆試的編程語言八孝。因為 JetBrain 家的 IntelliJ 實在是太香了董朝,相比其他語言的編輯器,不僅有 psvm
和 sout
這樣的快捷命令(你要是連這都不知道干跛,趕緊面壁去)子姜,而且可以幫你檢查出很多筆誤,比如說 while
循環(huán)里面忘記遞增變量楼入,或者 return
語句錯寫到循環(huán)里這種由于疏忽所導(dǎo)致的問題闲询。
C++ 也還行,但是我覺得沒有 Java 好用浅辙。我印象中 C++ 連個分割字符串的 split
函數(shù)都沒有扭弧,光這點我就不想用 C++ 了……
還有一點,C++ 代碼對時間的限制高记舆,別的語言時間限制 4000ms鸽捻,C++ 限制 2000ms,我覺得挺吃虧的泽腮。怪不得看別人用 C++ 寫算法御蒲,為了提高速度,都不用標(biāo)準(zhǔn)庫的 vector
容器诊赊,非要用原始的 int[]
數(shù)組厚满,我看著都頭疼。
Python 的話我刷題用的比較少碧磅,因為我不太喜歡用動態(tài)語言碘箍,不好調(diào)試。不過這個語言的奇技淫巧太多鲸郊,如果你深諳 Python 的套路丰榴,可以在某些時候投機(jī)取巧。比如說我們前文寫到的 表達(dá)式求值算法 是一個困難級別的算法秆撮,但如果用 Python 內(nèi)置的 exec
函數(shù)四濒,直接就能算出答案。
這個在筆試?yán)锟隙ㄊ呛苷急阋说模驗橹罢f了盗蟆,我們要的是結(jié)果戈二,沒人在乎你是怎么得到結(jié)果的。
PS:我認(rèn)真寫了 100 多篇原創(chuàng)喳资,手把手刷 200 道力扣題目挽拂,全部發(fā)布在 labuladong的算法小抄,持續(xù)更新骨饿。建議收藏亏栈,按照我的文章順序刷題,掌握各種算法套路后投再入題海就如魚得水了宏赘。
解法代碼分層
代碼分層應(yīng)該算是一種比較好的習(xí)慣绒北,可以增加寫代碼的速度和降低調(diào)試的難度。
簡單說就是察署,不要把所有代碼都寫在 main
函數(shù)里面闷游,我一直使用的套路是,main
函數(shù)負(fù)責(zé)接收數(shù)據(jù)贴汪,加一個 solution
函數(shù)負(fù)責(zé)統(tǒng)一處理數(shù)據(jù)和輸出答案脐往,然后再用諸如 backtrack
這樣一個函數(shù)處理具體的算法邏輯。
舉個例子扳埂,比如說一道題业簿,我決定用帶備忘錄的動態(tài)規(guī)劃求解,代碼的大致結(jié)構(gòu)是這樣:
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 主要負(fù)責(zé)接收數(shù)據(jù)
int N = scanner.nextInt();
int[][] orders = new int[N][2];
for (int i = 0; i < N; i++) {
orders[i][0] = scanner.nextInt();
orders[i][1] = scanner.nextInt();
}
// 委托 solution 進(jìn)行求解
solution(orders);
}
static void solution(int[][] orders) {
// 排除一些基本的邊界情況
if (orders.length == 0) {
System.out.println("None");
return;
}
// 委托 dp 函數(shù)執(zhí)行具體的算法邏輯
int res = dp(orders, 0);
// 負(fù)責(zé)輸出結(jié)果
System.out.println(res);
}
// 備忘錄
static HashMap<String, Integer> memo = new HashMap<>();
static int dp(int[][] orders, int start) {
// 具體的算法邏輯
}
}
你看這樣分層是不是很清楚阳懂,每個函數(shù)都有自己主要負(fù)責(zé)的任務(wù)梅尤,如果哪里出了問題,你也容易 debug岩调。
倒不是說要把代碼寫得多規(guī)范巷燥,至于 private
這種約束免了也無妨,變量用拼音命名也 OK号枕,關(guān)鍵是別把代碼直接全寫到 main
函數(shù)里面缰揪,真的亂,不出錯也罷葱淳,一旦出錯钝腺,估計要花一番功夫調(diào)試了,找不到問題亂了陣腳蛙紫,那是要盡量避免的拍屑。
考前復(fù)習(xí)策略
考前就別和某一道算法題死磕了途戒,不劃算坑傅。
應(yīng)該盡可能多的看各種各樣的題目,思考五分鐘喷斋,想不出來解法的話直接看別人的答案唁毒∷廛睿看懂思路就行了,甚至自己寫一遍都沒必要浆西,因為比較浪費時間粉私。
筆試的時候最怕的是沒思路,所以把各種題型都過目一下近零,起碼心里不會慌诺核,只要有思路,平均一道題二三十分鐘搞定還是不難的久信。
前面不是說了么窖杀,沒有什么問題是暴力窮舉解決不了的,直接用 回溯算法套路框架 硬上裙士,大不了加個備忘錄入客,不就成 動態(tài)規(guī)劃套路框架 了么,再大不了這題我不做了么腿椎,暴力過上 60% 的 case 也挺 OK 的桌硫。
別的不多說了,套路這個東西啃炸,說來簡單铆隘,一點就透,但問題是不點就不透南用。本文我簡單介紹了幾個筆試算法的技巧咖驮,各位好好品味~
最后,請秋招的同學(xué)多向身邊的朋友推薦 labuladong 公眾號训枢。算法真的沒那么難托修,這一切只是手段而已,過算法筆試拿 offer 才是目的恒界。為了達(dá)到目的睦刃,套路是必須的,可以少走很多彎路十酣,你的朋友會感謝你的涩拙,我也會感謝你的??
_____________
我的 在線電子書 有 100 篇原創(chuàng)文章,手把手帶刷 200 道力扣題目耸采,建議收藏兴泥!對應(yīng)的 GitHub 算法倉庫 已經(jīng)獲得了 70k star,歡迎標(biāo)星虾宇!