一句話結論:演算法負責「這件事該怎麼想」,AI 負責「每一步做快一點」。先判斷問題屬於哪一種題型,再把最花時間的步驟交給 AI,最後自己驗收。
為什麼刷題的東西能搬進生活
刷完一輪題之後,我發現真正留下來的不是某一題的解法,而是讀題時的幾個反射動作:
- 限制是什麼:時間、預算、體力、不能做的事。
- 要讓什麼變大或變小:效率、花費、遺憾、風險。
- 哪些東西可以犧牲:完美、一次到位、別人的期待。
面試題會把這三件事寫在題目裡;生活裡的決定也有同樣三件事,只是沒有人幫你寫出來。所以這篇不是要把生活寫成程式,而是把題型當成「辨認問題的捷徑」。看出一件事長得像哪一種題,就大概知道該怎麼做、要避開哪些坑。
AI 在這裡的角色很單純:降低每一步的成本。查資料、列選項、算數字、整理紀錄、寫第一版草稿,AI 都做得快。但「這是哪一種題型」「什麼時候該停」「哪個結果可以接受」,還是要由你決定。
怎麼讀這篇
為了讓內容具體,每一節都用同一個虛構人物當例子:小明,快三十歲,在台北上班。他遇到的都是一般人日常會碰到的事,有時會找朋友小華幫忙,有些事也會牽涉到他的家人。情境是虛構的,數字是為了示範而設定的。
二十個演算法分成五類,每一節都用同樣的結構:
- 題目的訊號:在刷題時看到什麼字眼會想到它
- 生活裡長什麼樣:幾個常見場景
- 怎麼做:可以照著做的步驟
- 例子:小明遇到的一個帶數字的實際情況
- 圖解:把演算法在這個例子裡怎麼一步步運作畫成一張圖,圖下方的說明會告訴你怎麼看
- AI 能幫什麼:先說 AI 適合做哪一步,再附一段「小明可以這樣問:」的提問範本,複製後換成你自己的情況就能用
- 常見誤用:什麼時候會用錯
二十個演算法各自解決一種形狀的問題,但真實的目標通常同時長成好幾種形狀。所以文章後段、延伸閱讀之前的「統合起來 一套依目標長出策略的演算法」一節,會把它們合成一套演算法:你給它目標和現在的狀況,它挑出該用哪幾個演算法、照什麼順序接起來,長出一套較好的策略。那一節同樣有詳細的說明和圖解。
不用一次讀完。先看下面的全貌,挑一個你最近剛好遇到的情況,直接跳到那一節;想先看全部怎麼接在一起,可以直接跳到延伸閱讀前的「統合起來」那一節。
先看全貌
怎麼看紀錄才不被雜訊騙
從很多選項裡挑一個
先做哪一件、怎麼排時間
大事拆小、碎事合併
習慣、空間和重試
第一類 看資料
生活裡最常見的錯,是用單一天、單一筆資料下結論。這一類演算法處理的是「怎麼看紀錄」。
滑動視窗與雙指針 看最近幾天而不是今天
題目的訊號:「連續」「最近 k 個」「某段區間內」「兩份已排序的清單」,例如 LC 643 的固定長度視窗平均、LC 986 的區間交集。
生活裡長什麼樣
- 練琴時間、睡眠、花費、心情每天都在跳。只看今天,昨天沒練就覺得全毀了,今天練得順又以為問題解決了。
- 想跟另一個人約時間,兩個人各有一份空檔清單,要找出重疊的部分。
怎麼做
- 選一個視窗長度。變化快的事用 7 天,養成類的事用 14 到 30 天。
- 每天加入新的一天、丟掉最舊的一天,只看視窗內的平均或達成率。總和不用每天從頭加:新的總和 = 昨天的總和 − 被丟掉那天 + 新加入那天。
- 只拿視窗跟視窗比,例如這 7 天跟上 7 天,不拿單日跟單日比。
- 雙指針的用法:把兩份清單都照時間排好,兩個指針各指一份的開頭,比較目前這兩段有沒有重疊,結束得比較早的那一段就往下移一格。這就是 LC 986 區間列表的交集。
例子:小明在學吉他,目標是「最近 7 天平均每天練 20 分鐘以上」。他連續 10 天的練習分鐘數是 20、25、0、20、30、15、30、10、0、5。第 3 天加班沒練,單看那天是 0,很容易覺得前功盡棄;但到第 7 天看最近 7 天,總和是 140 分鐘、平均 20.0 分鐘,剛好達標。之後每天只做一次減法和一次加法:第 8 天丟掉第 1 天的 20、加上第 8 天的 10,總和變成 130,平均約 18.6;第 9 天丟掉第 2 天的 25、加上 0,總和 105,平均 15.0;第 10 天丟掉第 3 天的 0、加上 5,總和 110,平均約 15.7。第 3 天的 0 被其他六天撐住,平均仍是 20.0;第 8 天一天偏低,平均只小降到 18.6;第 8 天起連續三天偏低,第 9、10 天的平均掉到 15 左右,才明顯反映出來。第 10 天的平均比第 9 天高一點,只是因為被丟出去的剛好是第 3 天的 0,不代表他已經回到正軌;這時該看的是第 8 天起生活裡發生了什麼。
| 第1天 | 第2天 | 第3天 | 第4天 | 第5天 | 第6天 | 第7天 | 第8天 | 第9天 | 第10天 | |
|---|---|---|---|---|---|---|---|---|---|---|
| 第7天 | 窗內 | 窗內 | 窗內 | 窗內 | 窗內 | 窗內 | 新 | |||
| 第8天 | 丟掉 | 窗內 | 窗內 | 窗內 | 窗內 | 窗內 | 窗內 | 新 | ||
| 第9天 | 丟掉 | 窗內 | 窗內 | 窗內 | 窗內 | 窗內 | 窗內 | 新 | ||
| 第10天 | 丟掉 | 窗內 | 窗內 | 窗內 | 窗內 | 窗內 | 窗內 | 新 |
約時間用的是雙指針。小明和小華想在週六碰面一小時,討論要不要一起報名吉他課。小明的空檔是 9–11 點、13–15 點、16–18 點;小華的空檔是 10–12 點、14–17 點,兩份都已照時間排好。第 1 次比 9–11 和 10–12,重疊 10–11 點,小明那段比較早結束,換小明的下一段。第 2 次比 13–15 和 10–12,沒有重疊,小華那段比較早結束,換小華的下一段。第 3 次比 13–15 和 14–17,重疊 14–15 點,小明那段比較早結束,換小明的下一段。第 4 次比 16–18 和 14–17,重疊 16–17 點,小華那段比較早結束,而小華的清單已經看完,停。4 次比較就找到全部 3 段重疊。兩份清單各有 m 段和 n 段時,最多只要比 m + n − 1 次;如果是 30 段和 40 段,最多比 69 次,而不是把 1,200 種組合都比一遍。
小明 9–11 點,小華 10–12 點
小明 13–15 點,小華 10–12 點
小明 13–15 點,小華 14–17 點
小明 16–18 點,小華 14–17 點
比 4 次就停,共 3 段重疊
AI 能幫什麼:計算和找異常。約時間也一樣,把兩份空檔清單貼上去,請它列出所有重疊的時段。
小明可以這樣問:
以下是我最近 21 天每天練吉他的分鐘數,每天一行,後面附當天備註(例如加班、聚餐、感冒)。請算出每天的 7 天移動平均,列出當天分鐘數跟前 7 天平均差最多的 3 天,並對照備註列出可能的原因。不要給一般性的練琴建議。
常見誤用:視窗太短,結果還是被雜訊帶著走;或者視窗太長,真的變差了也要好幾週才看得出來。雙指針則要先把兩份清單都照時間排好,沒排序就移動指針,會漏掉重疊的時段。
延伸閱讀:雙指針與滑動視窗實戰
前綴和 隨時知道累計到哪裡
題目的訊號:「區間總和」「從開頭到現在」「和為 k 的子陣列」,例如 LC 303、LC 560。
生活裡長什麼樣
- 這個月的預算還剩多少,照現在的速度會不會超支。
- 一年想讀 24 本書,到現在讀了幾本,是超前還是落後。
- 任意一段時間的總量:上週三到這週二一共花了多少、練了幾個小時的琴。
怎麼做
- 每天記錄的時候,同時記一個「累計」欄位:今天的累計 = 昨天的累計 + 今天的數字。
- 想知道某段區間的總量,用結尾那天的累計減掉開始前一天的累計,不用把每一天加起來。
- 把累計跟「理想進度線」放在一起看,就知道自己超前還是落後。理想進度 = 總預算 ÷ 總天數 × 已經過的天數。
- 想知道接下來每天還能花多少:(總預算 − 今天的累計)÷ 剩下的天數。
例子:小明九月的生活費預算是 15,000 元,九月有 30 天,理想進度是每天 500 元。他每天記帳時順手記累計:第 6 天 3,200 元,第 9 天 5,300 元,第 12 天 7,000 元,第 17 天 10,500 元,第 18 天 11,400 元。第 18 天的理想進度是 9,000 元,他已經多花了 2,400 元。剩下 3,600 元要撐 12 天,平均每天只能花 300 元;如果照目前每天約 633 元(11,400 ÷ 18)的速度,月底會花到 19,000 元,超出 4,000 元。想知道第 10 天到第 17 天花了多少,就用第 17 天的累計減掉第 9 天的累計:10,500 − 5,300 = 5,200 元,平均每天 650 元,比理想進度多 150 元。一個減法就有答案,不用把 8 天的帳一筆一筆加起來。單獨一天也一樣:第 18 天當天花了 11,400 − 10,500 = 900 元,那天他跟朋友聚餐。
AI 能幫什麼:把流水帳整理成累計表,並畫出跟理想進度的差距。
小明可以這樣問:
以下是我九月 1 日到 18 日每天的支出,每行是日期、金額、類別。我這個月的預算是 15,000 元。請加一欄每日累計,再算出照目前的平均速度,月底會花多少;如果會超過 15,000 元,列出花最多的三個類別,以及剩下 12 天每天平均要控制在多少錢以內。另外用累計相減,算出 1 到 7 日、8 到 14 日、15 到 18 日各花了多少。
常見誤用:中間漏記了幾天,累計就會一直偏低。漏記的天數要補「估計值」並標記,而不是空著當成零。另一個常見的錯是差一天:要算第 10 到 17 天,減的是第 9 天的累計,不是第 10 天的;減錯了就會漏掉第 10 天那一筆。
延伸閱讀:雜湊與字串實戰 裡 LC 560 用的就是前綴和
單調堆疊 被完全比下去的選項直接刪掉
題目的訊號:「下一個更大的元素」「再過幾天會更暖」,例如 LC 739、LC 496。核心想法是:一路往下看的時候,只留下「還有可能是答案」的候選,被新出現的選項全面比下去的,就永遠不用再考慮。
生活裡長什麼樣
- 看房子、挑手機、找工作:選項一個接一個出現,你得記住前面看過的。
- 比價:同一件東西在不同時間、不同店家出現不同價格。
怎麼做
- 先決定兩到三個最重要的條件,而且要能用數字比,例如租房的「租金」和「通勤時間」。
- 每看到一個新選項,就跟候選清單上的比:如果新的在每個條件上都不比某個舊的差,而且至少一項比較好,舊的那個就從清單刪掉。
- 反過來,如果清單上已經有某一個在每個條件上都不比新的差,新的就不用放進清單。
- 清單上永遠只留「沒有被完全比下去」的選項,最後只需要在這幾個之間取捨。
嚴格來說,LC 739 的單調堆疊一定會把新元素放進去,只從頂端刪掉被它比下去的;第 3 步「新的被比下去就不放」是把同一個想法延伸到兩個條件,叫做「只留沒被支配的選項」。
例子:小明在台北找房子,只比兩個條件:月租和單程通勤時間。第 1 間 A 是 18,000 元、40 分鐘,先放進候選清單。第 2 間 B 是 16,000 元、35 分鐘,兩項都比 A 好,A 直接刪掉。第 3 間 C 是 14,000 元、55 分鐘,比 B 便宜但比較遠,跟 B 互有勝負,兩個都留著。第 4 間 D 是 15,000 元、30 分鐘,兩項都比 B 好,B 刪掉;D 跟 C 互有勝負,都留著。第 5 間 E 是 14,000 元、45 分鐘,租金跟 C 一樣、通勤短 10 分鐘,C 刪掉;E 跟 D 互有勝負,都留著。第 6 間 F 是 17,000 元、50 分鐘,D 和 E 兩項都比它好,F 根本不用放進清單。看完 6 間,清單上只剩 D 和 E,小明只需要回答一個問題:每個月多付 1,000 元,換單程少 15 分鐘,值不值得?以一個月上班 22 天、每天來回兩趟算,省下的通勤是 15 × 2 × 22 = 660 分鐘,也就是 11 小時,等於每省 1 小時通勤付約 91 元。之後就算看到第 10 間,清單上通常也只會剩兩三間。
AI 能幫什麼:從一堆選項裡挑出沒被比下去的那幾個。
小明可以這樣問:
以下是我這三週看過的 10 間房子,每間有月租、單程通勤分鐘數、坪數(租金和通勤越低越好,坪數越大越好)。如果某一間在三個條件上都不比另一間差,而且至少一項比較好,就算把另一間「比下去」。請列出沒有被任何一間比下去的房子,並說明每一間各自的取捨;被刪掉的房子,請寫出它是被哪一間比下去的。
常見誤用:條件列太多。條件一多,幾乎每個選項都會在某一項勝出,結果什麼都刪不掉。只留真正會影響決定的兩三個。另一個錯是把互有勝負的也刪掉:只要舊的還有一項比新的好,例如比較便宜,就要留著,不然真正的好選項會被提早丟掉。
第二類 做選擇
這一類處理的是「從很多選項裡挑一個或一組」,以及「要多花多少力氣挑」。
雜湊表 讓常見的決定直接查表
題目的訊號:同一個查詢反覆出現,用空間換時間,例如 LC 1 Two Sum。
生活裡長什麼樣:每天都要決定早餐吃什麼、穿什麼、超市買什麼、週末去哪裡、要不要接受某種邀約。每個決定都很小,加起來卻會把精神耗光。
怎麼做
- 列出一週內重複做了三次以上的小決定。
- 每個寫一個預設答案,存在你每天會看到的地方。
- 遇到時直接查,不重新想;想換隨時可以換,只是不用每次從零開始。
- 遇到表上沒有的情況,想一次,再把答案補進表裡,下次就查得到。
- 每個月檢查一次,把不再適用的預設改掉。
例子:小明記了一週,發現有六種小決定各出現三次以上,加起來 25 次:平日早餐 5 次、午餐 5 次、明天穿什麼 5 次、同事臨時請託 4 次、週末做什麼 3 次、網購要不要買 3 次。他替每一種寫一個預設答案,存在手機備忘錄的第一則。第二週這些問題又出現了 25 次,其中 21 次直接照表做;剩下 4 次是表上沒有的情況,例如下雨天不想出門買早餐,他想一次之後就把答案補進表裡。
燕麥優格、火腿蛋三明治、地瓜配豆漿,週一到週三各一種,週四再從頭輪。
便當店、麵店、自助餐,照固定順序。
一天拿一套,早上不用站在衣櫃前想。
知道期限和時數,再決定答不答應。
清單平常想到就加,週五晚上挑一件就好。
先放進購物車,三天後還想要才買。
第一次遇到,想好答案後寫進表裡,下次直接查。
AI 能幫什麼:替 AI 建一張屬於你的雜湊表。
小明可以這樣問:
以下是我的偏好,之後回答都請照這些條件:我不吃海鮮、每餐預算 120 元以內、平日早上只有 15 分鐘準備、住處只有電鍋和微波爐、喜歡簡單不花俏的做法。請根據這些,給我五個平日早餐組合,每個列出材料和準備時間。我會從中挑兩個加進現在三種輪流的清單。
把這份偏好存起來,每次發問都附上,AI 就不會每次問一樣的問題,也比較少給出明顯不適用的建議。
常見誤用:預設變成枷鎖。預設是為了省力,不是為了不再做選擇;生活改變了,預設也要跟著改。另一個誤用是一次寫太多條,自己也記不住,查表反而比重想還慢;先從出現最多次的五、六種開始。
延伸閱讀:雜湊與字串實戰
二分搜尋 找剛好夠的那個量
題目的訊號:答案落在一個範圍內,而且有單調性,也就是多一點一定比較好或一定比較差。LC 875 吃香蕉的珂珂,問的就是「剛好來得及的最慢速度」。
生活裡長什麼樣:幾點睡隔天才有精神、咖啡喝幾杯剛好、每天練琴或讀書多久才不會隔天就放棄、某樣東西的預算抓多少、冷氣設幾度剛好。
怎麼做
- 定出合理範圍的上下限。
- 確認有沒有單調性:在這個範圍裡,多一點是不是一定比較好(或一定比較差)。
- 從中間值開始試,每個值至少試幾天,用前面的滑動視窗看結果。
- 太多就往下半段找,不夠就往上半段找,直到範圍小到差別不重要為止。
例子:小明開始學吉他,想找出每天練多久是他「撐得住」的最長時間。標準是一週至少練 5 天,範圍抓 10 到 90 分鐘。練得越久越難天天做到,所以有單調性。第 1 週試中間的 50 分鐘,只練了 3 天,太多,答案在 10 到 50 之間;第 2 週試 30 分鐘,練了 6 天,撐得住,答案在 30 到 50 之間;第 3 週試 40 分鐘,練了 4 天,又太多,範圍剩 30 到 40;第 4 週試 35 分鐘,練了 5 天,剛好達標,範圍剩 35 到 40。差 5 分鐘已經不重要,結論是現在每天練 35 分鐘。四週就找到;如果從 10 分鐘開始每週加 5 分鐘慢慢試,要試到 40 分鐘失敗才知道答案,得花 7 週。
AI 能幫什麼:設計實驗,並幫你找出沒控制好的變數。
小明可以這樣問:
我想找出每天練吉他「撐得住」的最長時間,範圍 10 到 90 分鐘,標準是一週至少練 5 天。請幫我設計一個用二分法的實驗計畫:每個值試幾天、每天記哪些指標、怎麼判斷要往上還是往下、範圍縮到多小就停。另外列出可能干擾結果的因素,例如加班、連假、感冒。
常見誤用:沒有單調性還硬用。睡越多不一定越有精神,超過某個時數反而會更昏,這時候要改成在小範圍內逐一比較。另一個誤用是每個值只試一天,雜訊會讓你往錯的方向砍半。
延伸閱讀:二分搜尋實戰
貪婪 每一步先選眼前最好的
題目的訊號:「最多能參加幾個活動」「最少需要幾次」「能不能跳到終點」,例如 LC 435、LC 55。貪婪的意思是每一步都先選當下最好的,而且不回頭。它只在「局部最好會導向整體最好」的題目才對。
生活裡長什麼樣
- 週六有好幾個活動時間重疊,想參加最多個。
- 手上很多事都有截止日,想讓延誤最少。
- 找零錢、湊整數,用最大面額先付。
怎麼做
- 想參加最多個活動:照結束時間排序,每次挑最早結束、而且跟已選的不衝突的那一個。早結束,留給後面的時間就多。
- 想讓最晚的那件事延誤最少:照截止日排序,最早截止的先做。這在排程理論裡叫最早截止優先。
- 用之前先問:每個選項的「價值」是不是都差不多?如果差很多,貪婪就可能出錯,要改用下一節的背包問題。
例子:小明這個週六有五個想參加的活動:瑜伽 9 點到 10 點、市集 9 點半到 12 點、讀書會 10 點半到 12 點、午餐聚會 12 點到 13 點半、看展 13 點到 15 點。照結束時間排好,從最早結束的開始挑:瑜伽 10 點結束,先選;市集 9 點半就開始,跟瑜伽重疊,跳過;讀書會 10 點半開始,不衝突,選;午餐聚會 12 點開始,剛好接上讀書會,選;看展 13 點開始,午餐聚會要到 13 點半才結束,跳過。最多參加三個。如果他先選看起來最吸引人的市集,市集佔掉 9 點半到 12 點,瑜伽和讀書會都會撞到,最後只能參加市集和午餐聚會兩個。
| 9:00 | 9:30 | 10:00 | 10:30 | 11:00 | 11:30 | 12:00 | 12:30 | 13:00 | 13:30 | 14:00 | 14:30 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 瑜伽 | 選上 | 選上 | ||||||||||
| 市集 | 跳過 | 跳過 | 跳過 | 跳過 | 跳過 | |||||||
| 讀書會 | 選上 | 選上 | 選上 | |||||||||
| 午餐聚會 | 選上 | 選上 | 選上 | |||||||||
| 看展 | 跳過 | 跳過 | 跳過 | 跳過 |
AI 能幫什麼:排序和檢查衝突。
小明可以這樣問:
以下是我這個週六想參加的五個活動和時間。請照結束時間排序,用「每次挑最早結束、又不衝突的」方法,排出我最多能參加幾個,並列出被排除的活動各跟哪一個衝突。另外,如果我一定要去看展,請先把看展固定下來,再重新排剩下的時間。
同樣的做法也能用在待辦:把每件事的截止日和預估時間給 AI,請它照截止日排序、算出每一件的預計完成時間,標出哪幾件會遲交、各遲幾天;如果有方法讓遲交的件數更少,請它另外說明。
常見誤用:在價值差很多的情況下用貪婪。挑最早結束的活動,能讓參加的「數量」最多,但不保證最「值得」;如果某個活動對你特別重要,要先把它排進去,再對剩下的時間用貪婪。例如小明最想去的是看展,就先把看展 13 點到 15 點固定,再對 13 點以前的時間用貪婪:瑜伽、讀書會,一樣是三個,只是午餐聚會換成了看展。
背包問題 有限的時間和預算裝最多價值
題目的訊號:「容量有限」「每個東西有重量和價值」「選或不選」,例如 LC 416、LC 322。這是動態規劃最經典的一種。
生活裡長什麼樣:週末只有 5 個小時、這個月只有 3,000 元的玩樂預算、行李箱只能放 7 公斤、這一季只能學一兩項新技能。
怎麼做
- 列出所有選項,每個寫兩個數字:要花多少(時間、錢、重量),以及對你的價值,用 1 到 10 分即可。
- 把明顯不划算的先刪掉:花得多、價值又低的。
- 選項少的時候,直接列出所有組合,挑總價值最高、又不超過容量的那一組。
- 選項多的時候,交給 AI 或試算表去算,你負責給分數。
例子:小明這個週日有 5 個小時空檔。原本還想去逛街,要 3 小時、只有 2 分,花得多又不重要,第一步就刪掉。剩下的選項是:練吉他 2 小時 6 分、讀小說 3 小時 7 分、整理房間 1 小時 3 分、跟小華吃飯 3 小時 8 分、看電影 2 小時 4 分。如果用貪婪、照「每小時的分數」挑:練吉他和整理房間每小時都是 3 分,最高,先選,用掉 3 小時;再來是跟小華吃飯(每小時約 2.7 分),加上去要 6 小時,放不下;讀小說(每小時約 2.3 分)也放不下;最後看電影放得下,剛好 5 小時、13 分。但把所有放得下的組合列出來,一共 15 種,最好的是跟小華吃飯加練吉他,也是 5 小時,卻有 14 分。這就是貪婪會出錯、要用背包問題的情況。
AI 能幫什麼:算組合,你負責給分數。
小明可以這樣問:
我這個週日有 5 小時空檔,以下是想做的事,每件附上需要的時間和對我的重要程度(1 到 10 分):練吉他 2 小時 6 分、讀小說 3 小時 7 分、整理房間 1 小時 3 分、跟小華吃飯 3 小時 8 分、看電影 2 小時 4 分。請找出不超過 5 小時、總分最高的組合,並列出第二好和第三好的組合讓我比較。
常見誤用:分數亂給。演算法只會照你給的分數算,分數不準,算出來的最佳解也不準。給分時想一下:一個月後回頭看,哪一件最不後悔。另一個誤用是只看一種容量:週末的限制常常不只時間,還有錢和體力,有兩種限制時,兩個都要寫進去再算。
延伸閱讀:動態規劃核心
最佳停止 看夠了就要決定
題目的訊號:這不是常見的刷題題目,而是機率裡的經典問題,常被叫做秘書問題:選項一個接一個出現,錯過就不能回頭,什麼時候該停下來選?
生活裡長什麼樣:找房子、找停車位、面試應徵者、在一段時間內決定要不要接受某個機會。看太少,可能錯過更好的;看太多,最好的可能早就錯過了。
怎麼做
- 估計你總共大概會看幾個選項,或者會花多長時間找。
- 前面約 37% 的部分只看不選,用來建立標準。
- 過了這個點,第一個比「前面看過的全部都好」的選項,就選它。
- 先想好退路:如果過了這個點一直沒遇到更好的,到期限時要怎麼辦,例如選最後看到的那一個,或延長找的時間。
這個 37% 來自數學上的最佳解,在「錯過就回不去、而且你只在乎選到最好的那一個」的條件下,這個策略選到最好選項的機率大約也是 37%,已經是能做到的最好。
例子:小明打算花一個月在台北找租屋,預計看 20 間左右。20 的 37% 約是 7,所以前 7 間只看、用同一份評分表打分數(滿分 100),分別是 62、70、55、78、66、73、60,最高的是第 4 間的 78 分,這就是門檻。從第 8 間開始,只要超過 78 分就決定:第 8 間 71 分、第 9 間 75 分都沒過;第 10 間 82 分,他就簽約,後面 10 間不用再看。82 分不一定是 20 間裡最高的,但在不能回頭的條件下,這個規則選到最好那一間的機會已經是最高的。
AI 能幫什麼:幫你估算總數和建立評分標準。
小明可以這樣問:
我打算在一個月內在台北找租屋,預計看 20 間左右。請幫我設計一份評分表(5 個以內的項目,總分 100),讓我在前 7 間建立標準,並告訴我從第 8 間開始怎麼判斷「比前面都好」。如果到最後都沒有遇到更好的,也請建議我怎麼收尾。
常見誤用:硬套 37%。真實生活常常可以回頭(例如前面那間還沒租出去),或者「夠好」就可以、不一定要最好。這兩種情況都應該更早下決定,而不是死守 37%。
探索與利用 新的要試多少
題目的訊號:這是機器學習和推薦系統的經典問題,常被叫做多臂吃角子老虎:已知不錯的選項,和還沒試過、可能更好的選項,要怎麼分配次數?
生活裡長什麼樣:常去的餐廳和沒去過的新餐廳、熟悉的工作方法和新工具、常聽的歌單和沒聽過的歌手、老朋友和新認識的人。
怎麼做
- 看你還會在這個情況裡待多久。時間還長,就多探索;快結束了,就多利用已知的好選項。剛搬到新城市的第一個月多試新餐廳,搬走前一個月就去最愛的那幾家。
- 給探索固定的比例,例如五次裡有一次試新的。機器學習裡類似的做法叫 epsilon-greedy:每次選擇時,有固定的機率 ε 隨機試新的,平均下來就是這個比例。
- 每次探索都記錄結果,讓下一次的判斷更準。
例子:小明剛從台中搬到台北工作,一週在外面吃 5 次晚餐。第 1 週他一家店都不認識,週一到週四每天試一家新的,週五回到這四家裡最喜歡的那家;第 2 週試 3 家新的;第 3、4 週各試 2 家;第 5 週起固定五次裡試一次,接近 epsilon-greedy 裡 ε = 20% 的做法;前四週逐步減少探索,相當於讓 ε 隨時間變小。前 8 週一共 40 餐,其中 15 餐在試新店、25 餐回到吃過覺得好的店。就算 15 家裡只有 4 家值得再去,他的「已知好選項」也從零變成 4 家,之後的晚餐越來越有把握。
| 週一 | 週二 | 週三 | 週四 | 週五 | |
|---|---|---|---|---|---|
| 第 1 週 | 試新 | 試新 | 試新 | 試新 | 回訪 |
| 第 2 週 | 試新 | 回訪 | 試新 | 回訪 | 試新 |
| 第 3 週 | 試新 | 回訪 | 回訪 | 試新 | 回訪 |
| 第 4 週 | 回訪 | 試新 | 回訪 | 回訪 | 試新 |
| 第 5 週 | 回訪 | 回訪 | 試新 | 回訪 | 回訪 |
| 第 6 週 | 回訪 | 回訪 | 回訪 | 回訪 | 試新 |
| 第 7 週 | 回訪 | 試新 | 回訪 | 回訪 | 回訪 |
| 第 8 週 | 回訪 | 回訪 | 回訪 | 試新 | 回訪 |
AI 能幫什麼:幫你列出探索的候選,並整理你的紀錄。
小明可以這樣問:
我剛搬到台北兩個月,以下是我吃過的 15 家店和評分(1 到 5 分)。請根據我評分高的店的共同點,推薦 5 種我還沒試過、可能會喜歡的類型,並建議我接下來一個月「試新店」和「回熟店」的比例。
常見誤用:只探索不利用,一直換新工具、新方法,從來沒有把一個用熟;或者只利用不探索,年復一年做同樣的事,錯過了更好的選擇。還有一種是比例從來不調整:剛搬來和已經住了好幾年,該探索的比例不一樣。
延伸閱讀:推薦系統的三層漏斗 裡談到推薦系統怎麼處理探索
第三類 排順序
這一類處理的是「先做哪一件」和「時間怎麼排」。
Heap 與 Top-K 同時只推進少數幾件
題目的訊號:要從一大堆東西裡持續取出最重要的 K 個,而且新資料一直進來,例如 LC 215、LC 347。
生活裡長什麼樣
- 待辦事項永遠比時間多。把全部攤開來排序很累,也沒有必要;你需要的只是隨時知道「現在最重要的那幾件」。
- 新的事情整天都在進來:主管臨時交辦、朋友傳訊息、突然想到的雜事。每進來一件就把整張清單重排一次,光是排序就花掉不少時間。
怎麼做
- 定一個容量 K。K 要小到不用看清單也記得住,例如每天的重點只放 3 件。
- 給每件事一個分數,標準先寫下來,例如有截止日的加分、會擋住別人的加分。
- 新的事情進來時,只跟這 K 件裡最弱的那件比;比它重要才換進來,被換掉的放回待排清單。分數一樣就不換,省下切換的成本。這就是 heap 的做法:最弱的那件永遠放在最上面,所以新事只要先跟它比一次,就知道能不能進來。
- 其他的事情不用排序,放著就好。
- 每天收工時把做完的拿掉,再從待排清單挑分數最高的補滿 K 件。只有補位的時候,才需要把待排清單看一遍。
例子:小明每天最多推進 3 件事。週二早上,他手上有 8 件事,各自打了 1 到 10 分:繳電費(今天截止)9 分、週五要交的報告初稿 8 分、幫小華看履歷(小華下週要投)6 分、預約牙醫 5 分、練吉他 30 分鐘 4 分、看完借來的書 3 分、研究日文課程 3 分、整理衣櫃 2 分。他挑出前 3 件,分數是 9、8、6,其他 5 件留在待排清單。三件裡最弱的是看履歷的 6 分,這就是今天的門檻。
10:30 主管要一份客戶資料,下午 3 點前要,小明給 7 分。他只拿 7 跟門檻 6 比:7 比 6 大,所以客戶資料換進來,看履歷退回待排清單,門檻變成 7。14:00 他想到要買週六桌遊夜的零食,給 3 分,比門檻 7 小,直接放進待排清單,前 3 件完全不用動。整天進來兩件新事,他只比了兩次,沒有重排過整張清單。
收工時,繳電費和客戶資料做完了,報告初稿還沒寫完,留著。待排清單現在有 7 件,他挑分數最高的兩件補進空出來的兩個名額:看履歷 6 分、預約牙醫 5 分。週三的前 3 件就是報告初稿、看履歷、預約牙醫。
AI 能幫什麼:從雜亂的清單裡提出前幾名,但標準要你先講。
小明可以這樣問:
以下是我現在所有的待辦,每件附上截止日、會不會擋到別人。請依這三個標準排序:一、有截止日的優先;二、會擋住別人的優先;三、對我這個月最在意的兩件事(把報告做好、每週練兩次吉他)幫助大的優先。列出前 3 名和理由,其他的不用排序。之後我再丟新的事情進來,只要告訴我它有沒有比第 3 名重要。
常見誤用:K 設太大。K 是 10 的時候,等於沒有重點。另一個誤用是排序標準沒講清楚,AI 就會用自己的猜測來排。還有一種是分數給了就不再看:前 3 件裡如果有一件卡住,例如在等別人回覆,就先把它退回待排清單,把名額讓給現在推得動的事。
延伸閱讀:Heap、Top-K 與區間實戰
區間合併 把零碎時間併成整塊
題目的訊號:一堆有開始和結束時間的區間,要合併重疊的部分,或算出最少需要幾間會議室,例如 LC 56、LC 253。
生活裡長什麼樣
- 一天被會議、訊息和小雜事切成碎片,碎片時間做不了需要專注的事。
- 家裡好幾個人週末都要用車,最少需要幾台車,這就是會議室問題。
怎麼做
- 前一天晚上寫下隔天的固定行程,照開始時間排好。吃飯、通勤也算,而且照實際會花的時間寫,不是照表定的時間。
- 由早到晚掃一遍:下一個行程的開始時間如果不晚於目前這段的結束時間,就是重疊或相鄰,併成一段,結束時間取比較晚的那個;否則就開始新的一段,中間空出來的就是空檔。
- 最需要專注的事放進最長的那段空白。
- 零碎的事(回訊息、繳費、預約)併成一到兩個批次,固定時段處理。
例子:小明明天的上班時間是 9:00 到 18:00,固定行程有 7 個:晨會 9:00 到 9:45(表定 9:30 結束,但最近常拖到 9:45,所以照實際的記)、一對一 9:30 到 10:00、跟設計師對稿 10:30 到 11:00、專案討論 11:00 到 12:00、午餐 12:00 到 13:00、部門例會 14:00 到 14:30、週報會議 17:00 到 17:30。
照開始時間掃一遍:晨會和一對一重疊,併成 9:00 到 10:00;對稿、專案討論、午餐一個接一個,併成 10:30 到 13:00;例會和週報會議各自獨立。7 個行程併成 4 段,忙碌時間共 270 分鐘。空檔是 10:00 到 10:30(30 分鐘)、13:00 到 14:00(60 分鐘)、14:30 到 17:00(150 分鐘)、17:30 到 18:00(30 分鐘),合計也是 270 分鐘,兩邊加起來剛好 9 個小時。
小明一開始沒把午餐寫進去,12:00 到 14:00 看起來有整整 2 小時;補上午餐再合併,只剩 13:00 到 14:00 的 1 小時。最長的空檔是 14:30 到 17:00:2 小時的專注工作放在 14:30 到 16:30,留 30 分鐘緩衝。10:00 和 17:30 開始的兩個 30 分鐘拿來集中回訊息,13:00 到 14:00 處理繳費、預約這類要打電話的雜事。
AI 能幫什麼:找出可以合併或挪動的時段。
小明可以這樣問:
以下是我明天的行事曆。晨會常常拖到 9:45,請照 9:45 結束計算。請合併重疊或相鄰的行程,列出所有空檔和長度,並建議:哪一段最適合放 2 小時的專注工作、哪些零碎空檔可以集中回訊息。如果挪動某個會議能多出更長的空檔,也請標出來。
常見誤用:把每個空檔都塞滿。留一點緩衝,行程一延誤,整天才不會跟著垮。另一個誤用是只照表定時間算:會議常常超時,照表定時間算出來的空檔會比實際的多。至於要不要挪別人的會議,牽涉到別人,還是要由你決定。
延伸閱讀:同一篇 Heap、Top-K 與區間實戰 的區間題
拓撲排序 先畫依賴再開始
題目的訊號:任務之間有「A 完成之後才能做 B」的關係,要判斷能不能全部完成、該照什麼順序做,例如 LC 207 課程表、LC 210。
生活裡長什麼樣
- 搬家、出國、裝修、換工作、辦活動,事情一件卡著一件。
- 這類事卡住的原因,常常不是事情太多,而是順序錯了:先做了要等別的事才能定案的那件,後面只好重做或多花錢。
怎麼做
- 把每件事寫成一張卡片。
- 每張卡片標出「它要等哪些事先完成」。它在等幾件事,就是它的入度。
- 沒有在等任何事的,也就是入度為 0 的,先做。做完就把它從別人的等待清單裡劃掉;某張卡片的等待清單被劃光,入度變成 0,就輪到它。
- 同時有好幾件入度為 0 時,它們可以一起進行;先開始要等別人處理最久的那件,例如等房東回覆、等官方審核。
- 如果發現 A 在等 B、B 又在等 A,那就是一個環,要先找出能打破循環的那件事。
例子:小明下個月底要從板橋搬到中山區。他寫了 8 張卡片,標出每一張在等什麼:
- 確定搬家日:等「跟房東確認退租日」和「簽新租約」。
- 預約搬家公司:等「確定搬家日」和「丟掉不要的東西」,因為報價要看東西有多少。
- 申請新家網路:等「簽新租約」(要有地址)和「確定搬家日」(要約安裝時間)。
- 打包:等「預約搬家公司」,紙箱是搬家公司送來的。
- 搬家當天:等「打包」。
- 跟房東確認退租日、簽新租約、丟掉不要的東西:不用等任何事,入度為 0。
所以第一輪同時做三件入度為 0 的事。做完之後,確定搬家日的等待清單被劃光,進入第二輪;第三輪是預約搬家公司和申請網路;第四輪打包;第五輪搬家。
他一開始卡在一個環:搬家公司要先知道東西有多少才肯報價,他卻想先知道報價才決定要丟多少。打破的方法是先自己丟一輪,再請搬家公司估價,所以「丟掉不要的東西」排在「預約搬家公司」前面。如果還沒跟房東確認退租日,就先付了搬家公司的訂金,退租日一改,訂金可能就拿不回來,這就是順序錯了。
入度為 0,不用等任何事
等退租日和新租約,兩件都在第一輪劃掉
各等兩件:第一輪劃掉一件,第二輪定了搬家日再劃掉一件
等搬家公司送紙箱
最後一步
AI 能幫什麼:列出一般步驟和依賴,再由你對照實際情況刪改。
小明可以這樣問:
我下個月底要從板橋搬到台北市中山區,一個人住,東西大概一台小貨車載得完。請列出要準備的事項,每一項標出它要等哪些事先完成,排出一個可行的順序,可以同時做的事放在同一輪。標出哪些事項需要我向房東、搬家公司或政府單位確認最新規定,例如押金怎麼退、地址變更要辦哪些手續。
常見誤用:完全相信 AI 列的清單。AI 列出的步驟可能過時或不完整,租約、押金、戶籍,或是出國時的簽證、稅務這類規定,一定要回到原始來源確認:合約本身、房東、政府網站。另一個誤用是把可以同時做的事硬排成一條線,例如等租約簽好才開始丟東西,整個流程就白白拉長。
延伸閱讀:圖論實戰
最短路徑 用最少步驟或最低成本到達
題目的訊號:「最少幾步」「最短時間」「最低成本」。每一步代價都一樣時用 BFS,例如 LC 127;每一步代價不同時用 Dijkstra,例如 LC 743。
生活裡長什麼樣
- 想找到某件事的負責人,最少要問幾個人。
- 想從現在的工作轉到另一個職位,要經過哪些中間步驟。
- 通勤有好幾種路線,各自花的時間和錢不同。
怎麼做
- 定義「節點」和「一步」:節點是狀態(例如你現在會的技能、你人在哪裡),一步是能讓你換到下一個狀態的行動。
- 決定要最小化什麼:步數、時間,還是錢。一次只能選一個標準,如果兩個都在乎,就先換算成同一個單位,例如把時間換算成錢。
- 從起點一層一層往外找:先看一步能到哪裡,再看兩步能到哪裡,最先碰到終點的,就是步數最少的路。已經到過的狀態不用再走一次。
- 如果每一步花的時間或錢差很多,只數步數會失準。這時改用 Dijkstra:每次都從「目前累積成本最低」的那個狀態往外走。終點第一次出現在鄰居裡時先別停,因為後面可能還有更便宜的路繞過來;要等到終點本身成了累積成本最低、輪到它被拿出來的那一刻,那條路的總成本才確定是最低的。
例子:小明在電商公司做了三年客服,想轉成 UX 設計師。起點是「客服,熟悉使用者常抱怨什麼」。一層一層往外看:
- 一步可到:上一門 UX 入門課(約 2 個月)、每月把客服前 10 大抱怨整理給產品團隊、準備申請設計研究所(約 6 個月)。
- 兩步可到:用課上學的方法重畫公司的退貨流程,做成第一個作品集案例(約 3 個月);跟著產品團隊旁聽使用者訪談;辭職去讀研究所(約 24 個月)。
- 三步可到:帶著作品集申請內部轉調成 UX 設計師(約 1 個月),碰到終點。同一圈裡,訪談那條路走到「把訪談發現寫成改版提案」,研究所那條路走到「找實習」,都還沒到。終點已經出現,就不再往外找。
最先碰到終點的路是「入門課 → 作品集 → 內部轉調」,3 步,約 2 + 3 + 1 = 6 個月。研究所那條路到第三步還在找實習(約 3 個月),之後還要再一步找正職(約 3 個月):4 步,約 6 + 24 + 3 + 3 = 36 個月,而且中間沒有收入。從現在的位置出發、每一步都有實際成果的路,通常比先離開原點再重新開始的路更短。在小明估得出時間的兩條路裡,步數最少的這條也最省時間,6 個月對 36 個月。訪談那條路還沒估時間,要比總時間,得先補上每一步的月數。步數最少和時間最短不一定是同一條路,例如某條路只有兩步、但其中一步要等一年;這時就要照第 4 步,改成比較累積的月數。
AI 能幫什麼:列出可能的中間狀態和步驟,你負責判斷每一步的實際成本。
小明可以這樣問:
我在電商公司做了三年客服,想在一年內轉成 UX 設計師,公司裡有產品設計團隊。請把可能的路線畫成幾個步驟,每一步寫出需要的時間、成本和風險,標出步數最少的路線和風險最低的路線。需要辭職的路線請特別標出來。
常見誤用:成本有負的。Dijkstra 要求每一步的成本不能是負的,生活裡如果某一步「反而讓你賺到時間」,就要重新定義成本,否則會算錯。另一個誤用是只數步數、不看每一步有多大:「讀研究所」和「上一門課」都算一步,但一個約 24 個月、一個約 2 個月,這時要照第 4 步改用累積成本比較。
延伸閱讀:圖論實戰
第四類 拆與組
這一類處理的是「大事怎麼拆小」和「零碎的東西怎麼合併」。
樹的拆解 把大目標拆到今天能做
題目的訊號:一個大問題由子問題組成,子問題還能再往下分。DFS 一路挖到底,BFS 一層一層展開,例如 LC 104、LC 102。
生活裡長什麼樣:「學會一個新語言」「做出一個自己的網站」「把家裡整理好」都太大,沒辦法直接放進今天。要一路拆下去,直到變成「今天可以打勾的一件事」。
怎麼做
- 先用 BFS:每個大目標只拆一層,確認方向都對,避免某個目標挖得很深、其他目標完全沒動。
- 真的要執行某個目標時,再對它做 DFS,一路拆到葉子。
- 葉子的大小是「一次坐下來就能做完」,大概一小時以內。還是做不完的,就再往下拆一層。
- 每天從葉子裡挑幾件放進今天。放得下幾件,看今天有多少時間。
例子:小明今年有三個大目標:「日文學到能在日本自己點餐」「架一個個人小網站」「整理租屋處」。
他先做 BFS,每個目標只拆一層,各拆成 3 塊,一共 9 塊。三個目標並排一看,他發現日文那一支原本寫的是「報名日檢」,可是他要的是能點餐,不是證照,於是換成「10 段點餐對話」。這種方向上的錯,要每個目標都先拆一層、放在一起比,才容易看出來。
這個月他最想先動的是網站,所以只對這一支做 DFS。他先挖「做出第一頁」:這塊大概要 2 小時,一次坐不完,再往下拆成三片葉子:選一個免費模板 40 分鐘、寫自我介紹 50 分鐘、換上自己的照片和配色 30 分鐘。三片加起來 120 分鐘,每片都在一小時內,就停在這裡。換照片和配色要等選好模板才能做,所以選模板排第一。
今晚他只有 1 小時。放進「選模板」以後剩 20 分鐘,剩下的葉子最短也要 30 分鐘,所以今天只放這一件。另外兩個大目標先停在第一層,等網站告一段落再往下挖。
第一層 3 塊;「報名日檢」已換掉
接下來要做 DFS 的這一支
第一層 3 塊
太大,今天放不進去
先挖「做出第一頁」,約 2 小時,一次坐不完
三片共 120 分鐘,每片都在 1 小時內,停
今晚 1 小時,放一片剩 20 分,不夠放下一片
AI 能幫什麼:產生第一版拆解,你負責刪改。把你現在的程度、每天有多少時間、不想要的做法講清楚,拆出來的片段才放得進你的日子。
小明可以這樣問:
我今年想架一個個人小網站,放自我介紹和 3 個做過的小作品。我會一點 HTML,平日晚上大概有 1 小時。請拆成 10 到 15 個具體片段,每個片段一次做完不超過一小時,並標出哪些有先後順序。不要包含需要付費請人做的項目。
常見誤用:拆得太細。把「選模板」拆成「搜尋模板」「比較三個」「下載」三個片段,反而增加管理成本。葉子的標準是「一次坐下來就能做完」,不是越小越好。另一個誤用是只做 DFS:一開始就把某個目標挖到最底,其他目標連第一層都沒有,等回頭才發現方向錯了。
延伸閱讀:二元樹與 BST 實戰
回溯與剪枝 在一堆組合裡找可行的
題目的訊號:要從很多選項組合出符合條件的方案。做一個選擇、往下走,走不通就退回;剪枝是提早放棄不可能的分支,例如 LC 39、LC 51。
生活裡長什麼樣:排旅行行程、排一週菜單、排讀書會的輪值、找家人都能配合的聚餐時間。組合的數量很快就會爆炸。
怎麼做
- 先寫出所有硬限制,例如預算上限、誰哪天不行、交通時間、店家公休。
- 依序做選擇,每做一個就檢查有沒有違反限制,違反了就退回上一步,換一個選擇。
- 剪枝:越早能判斷「這條路不可能」,就越早放棄。先排限制最多的部分,例如先排只有一天能去的景點;先檢查一次能刪掉一大片的條件,例如預算:一家餐廳超出預算,它的所有日期都不用再看。
- 剩下的可行方案,再依偏好挑。偏好是軟限制,留到最後用,不要拿來剪枝。
例子:小明要排一次家庭聚餐,五個人:小明、爸爸、媽媽、妹妹、奶奶。候選時間有 4 個:週五晚上、週六中午、週六晚上、週日中午。候選餐廳有 3 家:火鍋店每人約 650 元,週日公休;台菜館五人合菜 3,800 元,等於每人 760 元,週六公休;義式餐廳套餐每人 1,100 元。預算是每人 800 元以內。
4 個時間乘 3 家餐廳,一共 12 種組合。小明照這個順序剪:
- 先看預算:義式餐廳每人 1,100 元,超過 800 元,整欄 4 種一次刪掉,剩 8 種。
- 再看人:爸爸週五晚上要加班,週五晚上整列刪掉。這一列只剩火鍋店和台菜館 2 種要刪,剩 6 種。
- 最後查公休:台菜館週六公休,刪掉週六中午和週六晚上 2 種;火鍋店週日公休,刪掉週日中午 1 種,剩 3 種。
可行的是週六中午火鍋店、週六晚上火鍋店、週日中午台菜館。再看偏好:奶奶比較喜歡中午吃,三家裡又只有台菜館有包廂可以慢慢聊,最後選週日中午的台菜館。
如果一格一格檢查三個條件,要看 36 次。先剪整欄、再剪整列,只要看 3 家餐廳的價位、4 個時間誰有空,再查剩下 6 格的公休,一共 13 次。
| 時間\餐廳 | 火鍋店 | 台菜館 | 義式餐廳 |
|---|---|---|---|
| 週五晚上 | 有人不行 | 有人不行 | 超出預算 |
| 週六中午 | 可行 | 公休 | 超出預算 |
| 週六晚上 | 可行 | 公休 | 超出預算 |
| 週日中午 | 公休 | 可行 | 超出預算 |
AI 能幫什麼:這是 AI 最好用的場景之一。把每一條限制寫成清單交給 AI,請它列出所有組合、標出每個被刪掉的組合違反哪一條,你只要核對它刪得對不對。排旅行行程也一樣:每天最多幾個景點、哪天下午有事、哪個景點要早上去、每天預算多少,都寫成限制。
小明可以這樣問:
我要排一次五個人的家庭聚餐。候選時間:週五晚上、週六中午、週六晚上、週日中午。餐廳:火鍋店每人約 650 元,週日公休;台菜館五人合菜 3,800 元,週六公休;義式餐廳套餐每人 1,100 元。硬限制:每人 800 元以內;我爸週五晚上要加班。偏好:奶奶比較喜歡中午,有包廂更好。請列出全部 12 種組合,標出每個被刪掉的組合違反哪一條,再從可行的組合裡推薦一個,並說明理由。
常見誤用:沒檢查 AI 的方案。AI 偶爾會產生看起來合理、其實違反某條限制的方案,例如把週六的台菜館也列成可行,你要逐條核對。另一個誤用是把偏好當成硬限制。如果小明把「一定要有包廂」也當成硬限制,就只剩週日中午台菜館一個選項;萬一那天訂滿,就一個都不剩,只能從頭再排。先用硬限制剪,偏好留到最後挑。
延伸閱讀:回溯法實戰
Union-Find 把其實是同一件的事併在一起
題目的訊號:「有幾個群組」「哪些東西是連在一起的」「合併重複」,例如 LC 547、LC 684。
生活裡長什麼樣
- 待辦清單裡有好幾條其實是同一件事的不同說法。
- 筆記、書籤、照片散在各處,想整理成幾個主題。
- 好幾個人各自寫了「誰跟誰是同一個專案」,想知道總共有幾個專案。
怎麼做
- 一次只看兩個項目,問:「這兩個是同一件事嗎?可以一起處理嗎?」是的話就把它們連在一起。
- 連在一起的項目,自動跟彼此的所有夥伴都屬於同一組,不用再一一比較。
- 全部看完後,每一組就是一件真正的事,或一個主題。每把兩個原本不同組的項目連起來,件數就少一件。
例子:小明的待辦清單有 12 條。他一次只看兩條,覺得是同一件事就連一條線:
- 「回覆房東訊息」和「問房東修水龍頭」:同一則訊息就能講完,連。
- 「回覆房東訊息」和「確認續約日期」:房東傳訊息就是在問要不要續約,連。
- 「確認續約日期」和「找出租約」:要翻租約才知道日期,連。
- 「訂位」分別和「問家人哪天有空」「查三家餐廳價位」連起來,這三條就是上一節的家庭聚餐。
- 「比較手機方案」分別和「問小華用哪家」「備份舊手機」連起來,都是換新手機的一部分。
一共連了 7 條線,每一條都接起兩個原本不同的組。12 條待辦,每連一條少一件,12 − 7 = 5,最後剩 5 件事:跟房東談續約和維修、家庭聚餐、換新手機,還有找不到夥伴的「繳水電費」和「還圖書館的書」。
注意「問房東修水龍頭」和「找出租約」從來沒有被直接比較過,但它們都連在同一串上,所以自然落在同一組。房東那四條合成一件之後,小明先翻出租約,再傳一則訊息把續約和水龍頭一起問完,聯絡房東一次就夠,不用來回好幾次。
如果小明又把「問房東修水龍頭」和「確認續約日期」連起來,件數不會再變少,因為它們早就在同一組;這條多出來的線,就是 LC 684 要找的那條邊。
4 條 → 聯絡房東一次
3 條 → 一個晚上排完
3 條 → 週末一次處理
找不到夥伴,照原樣做
找不到夥伴,照原樣做
AI 能幫什麼:AI 很擅長判斷「這兩件是不是同一件」。兩兩比較的話,12 條就有 66 對,40 條有 780 對,清單一長就很適合交給 AI 做第一輪,你再檢查它併得對不對。
小明可以這樣問:
以下是我的 12 條待辦。請找出其實是同一件事、或可以一起處理的項目,把它們分組,每組給一個新的名稱,並用一句話說明每兩條為什麼連在一起。不要刪除任何一條,只做分組;找不到夥伴的就自己一組。
常見誤用:分得太粗。把「工作」或「家裡的事」整個當成一組沒有幫助,分組的目的是讓你一次處理完一件事。判斷標準是「能不能一次處理完」,不是「有沒有關係」:「繳水電費」和房東那組都跟租屋處有關,但繳費在手機上一分鐘就做完,不用等房東,所以小明讓它自己一組。
延伸閱讀:圖論實戰
動態規劃 記住做過的解
題目的訊號:同樣的子問題反覆出現,把子問題的答案存起來,下次直接拿來用;今天的狀態只取決於昨天的狀態和今天的選擇,例如 LC 70、LC 198。
生活裡長什麼樣
- 每週都重新想一次菜單、每次出差都重新列一次行李、每次寫報告都從空白頁開始,這些都是在重算已經解過的子問題。
- 習慣的連續天數就是最簡單的狀態轉移:今天的連續天數,只看昨天的連續天數和今天有沒有做。小明練日文,昨天是連續 6 天;今天有練就變 7 天,今天沒練就歸零。他只要記住昨天那個數字,不用回頭翻整本紀錄。
怎麼做
- 做完一件以後還會再做的事,花五分鐘把它存成模板或清單。
- 下次從模板開始改,而不是從零開始。
- 每次用完模板,把這次多想到的補進去,模板就越來越好。寫成狀態轉移就是:第 n 次的模板 = 第 n − 1 次的模板 + 這次新想到的東西。
例子:小明第一次出差去台中,從零開始列行李清單,想了 35 分鐘,列了 18 項,到了才發現忘了帶充電線。回來後他把清單存成模板,順手補上充電線,變成 19 項。
- 第 2 次:照模板勾選 8 分鐘,再花 2 分鐘補上「名片」,一共 10 分鐘,模板變成 20 項。
- 第 3 次:勾選 4 分鐘,補上「折疊傘」2 分鐘,一共 6 分鐘,模板變成 21 項。
- 第 4 次:勾選 3 分鐘,沒有新東西要補,模板維持 21 項。
- 第 5 次:一樣只勾選,3 分鐘,沒有新東西要補。
第 5 次只花 3 分鐘,不到第一次的十分之一。省下的不是打字的時間,而是「想」的時間:「要帶什麼」這個子問題,前幾次已經解過、存起來了。週會紀錄、報告、旅行計畫都是一樣。
AI 能幫什麼:讓 AI 順手把過程整理成模板。做完一件會重複的事,就請 AI 把這次的清單或步驟整理成可以重複用的格式;下次把模板和這次的不同之處一起交給它改。季度回顧、週會紀錄也能這樣做。
小明可以這樣問:
這是我第一次出差臨時列的行李清單,一共 18 項,到了才發現忘了帶充電線。請幫我整理成一份可以重複用的出差行李模板:補上充電線,分成證件、衣物、電子產品、工作用品四類,並標出只有過夜才需要的項目。下次出差我會直接把模板給你,再告訴你這次要去幾天。
常見誤用:模板太多,找不到。把模板集中放在一個地方,命名一致,例如都用「模板」開頭。另一個誤用是存了就不再更新:用完不把新想到的補回去,模板會慢慢跟實際脫節,久了又退回從零開始。
延伸閱讀:動態規劃核心
第五類 長期運作
這一類處理的是「長期下來的事」:習慣、空間和重試。
鏈結串列 把新習慣接在舊習慣後面
題目的訊號:節點一個接一個,插入新節點只需要改前一個節點的指向,反轉串列 LC 206 就是一個一個改指向;快慢指標可以偵測串列有沒有繞成一個圈,例如 LC 141。LC 142 再進一步,找出環是從哪一個節點開始的。
生活裡長什麼樣
新習慣最難的部分是「什麼時候做」。把它接在一個已經很穩定的動作後面,就像在串列裡插入一個新節點:只改前一個動作的「下一步」,其他動作都不用動。
- 想學一樣新東西,例如日文或吉他,卻一直找不到固定的時間。
- 早上的流程本來很順,硬塞進一件新事,整串就亂掉。
- 每隔一陣子就回到同一個狀態,例如又開始熬夜、又開始拖延同一類事。
怎麼做
- 列出每天一定會做的動作:起床、刷牙、倒咖啡、到公司、吃完午餐、洗澡。
- 把新習慣接在其中一個後面,格式是「在某某之後,我會……」。
- 一個節點後面一次只接一個新習慣,穩定了再接下一個。
- 先訂好「穩定」的標準,例如兩週裡做到 12 天,達到了才接下一個。
- 如果發現自己一再繞回同一個狀態,把它當成一個環,找出進入環的那個節點。
例子:小明想開始學日文,但一直說「有空再背」,一個月過去,一個單字都沒背。他先列出每天早上一定會做的事:起床、刷牙、倒咖啡、搭捷運、到公司。這五個動作他幾乎天天都做,是很穩的節點。
- 第 1、2 週:只插入一個新節點,「倒完咖啡之後,背 5 個日文單字」。14 天裡做到 12 天,一共背了 60 個單字。
- 他訂的穩定標準是「兩週裡至少 12 天」,剛好達到,才接下一個。
- 第 3 週:插入第二個節點,「坐上捷運之後,聽一集 10 分鐘的日文 podcast」。車程 25 分鐘,聽完還有 15 分鐘的餘裕。
舊的節點只改了兩個指向:倒咖啡的下一步從搭捷運改成背單字,搭捷運的下一步從到公司改成聽 podcast。新節點自己的下一步則接回原本的位置:背單字接搭捷運,聽 podcast 接到公司。起床、刷牙、到公司都沒有動。
下一步原本是搭捷運,改成背單字
第 1 週插入,兩週做到 12 天
下一步原本是到公司,第 3 週改成 podcast
第 3 週插入,一集 10 分鐘
鏈的最後一個節點
快慢指標在生活裡的用法是偵測循環。在串列裡,快指標一次走兩步、慢指標一次走一步,如果有環,快的遲早會從後面追上慢的;LC 142 接著找出環的入口。生活裡不用真的跑兩個指標,重點是兩件事:先承認「這是一個環」,再找出入口。如果你發現自己每隔一陣子就回到同一個狀態,例如又開始熬夜、又開始拖延同一類事,入口通常是某個觸發點。
第 3 週結束時,小明把兩個月的紀錄交給 AI 整理,發現 9 次熬夜裡有 7 次,前一個節點都是「睡前躺在床上滑手機」。開始背單字的這三週,他只漏掉 2 天,就是第 1、2 週那 2 天,前一晚也都熬夜了。找出這個入口,比責怪自己有用:要改的是通往入口的那一步,例如下班回家先把手機放在客廳充電,這樣躺上床之後,下一步就接不到滑手機。
11 點前睡,不在環裡
9 次熬夜裡有 7 次從這裡開始
凌晨 1 點後才睡
倒完咖啡就走,跳過背單字
又躺回床上滑手機
AI 能幫什麼:幫你挑一個夠穩的錨點,也幫你從紀錄裡找出反覆出現的模式和觸發點。
小明可以這樣問:
以下是我過去兩個月的每日紀錄(睡覺時間、當天備註;最近三週另外記了早上有沒有背日文單字)。請找出熬夜反覆出現的模式:通常發生在星期幾、前一天或當天有什麼共同點,以及在有背單字紀錄的這三週裡,熬夜的隔天早上是不是比較容易斷。只列出你在資料裡看得到的模式,不要推測心理原因。
常見誤用:接在不穩定的動作後面。如果「週六上日文課」本身還沒養成,就不要把新習慣接在它後面。另一個是一次插入好幾個新節點:同一個早上同時加背單字、聽 podcast、寫日記,只要一個斷掉,後面幾個常常跟著斷,也分不出是哪一個出了問題。
延伸閱讀:鏈結串列實戰
LRU 快取 空間滿了先淘汰最久沒用的
題目的訊號:容量有限的快取,滿了要淘汰「最久沒被用到的」那一個,例如 LC 146。標準做法是雜湊表加雙向鏈結串列:用到的移到最前面,滿了從最後面拿掉,兩個動作都是 O(1)。
生活裡長什麼樣
空間永遠不夠,問題是該丟哪一個。
- 衣櫃塞滿,換季時不知道該收掉或捐掉哪些。
- 書架放不下新買的書。
- 手機主畫面、廚房櫃子、電腦桌面上的檔案,越堆越多。
怎麼做
- 每次用到某樣東西,就把它放回「最前面」,例如衣服穿過就掛回衣櫃最右邊。
- 一段時間後,最左邊的就是最久沒用的。
- 空間滿了,從最久沒用的開始考慮淘汰。
- 淘汰之前,先把例外拿出來:季節性的、緊急用的、有紀念價值的。
例子:小明的衣櫃只有一根掛桿,剛好掛得下 60 個衣架,已經全滿。4 月 1 日,他把所有衣架都朝同一個方向掛;之後每穿過一件,掛回去時一律掛到最右邊;如果衣架還是原本的方向,就把它反過來,已經反過來的就維持不動。7 月 1 日和 9 月 1 日,他各在掛桿最右邊夾一個夾子當分隔。衣架方向告訴他「半年內有沒有穿」,位置告訴他「多久以前穿的」。到了 10 月 1 日,剛好半年:
- 衣架反過來的有 38 件:9 月 1 日的夾子右邊,也就是最近 1 個月穿過的,有 20 件;兩個夾子之間,1 到 3 個月前穿過的,有 12 件;7 月 1 日的夾子左邊,3 到 6 個月前穿過的,有 6 件。
- 衣架沒反過來、半年沒穿的有 22 件。
- 這 22 件裡,先拿掉例外:冬季外套 3 件(4 月到 10 月本來就不會穿)、正式場合用的西裝 1 套。剩下 18 件是淘汰候選。
- 他要空出 12 格,給換季時從收納箱拿出來的毛衣和厚外套。他從 18 件候選裡,挑出已經不合身或破損的 12 件,捐出或回收;另外 6 件還在猶豫,留在掛桿最左邊。
整理完,掛桿上剩 48 件、空出 12 格。下次空間又不夠時,第一批就是那 6 件,再來是 3 到 6 個月前穿過的 6 件。
書架也可以照做:翻過的書放回最左邊,一段時間後,最右邊那幾本就是最久沒翻的。
AI 能幫什麼:幫你決定「最久沒用」的門檻和例外。
小明可以這樣問:
我用衣架反向的方法觀察了半年:衣櫃 60 件衣服裡,有 22 件半年沒穿,其中冬季外套 3 件、正式場合用的西裝 1 套。我想空出 12 個衣架。請幫我列一套規則:多久沒穿就該考慮淘汰、剩下 18 件候選要照什麼順序處理(例如不合身、破損、同類太多件),以及哪些類型的衣服應該當成例外。
常見誤用:沒有例外。有些東西一年只用一次,但非常重要,例如冬天的外套、急救包。淘汰規則要先排除這些季節性和緊急用的東西。觀察期太短也會出錯:小明只看了 4 月到 10 月,看不出冬天的衣服有沒有在穿,所以冬季外套要靠例外清單保住。另外,LRU 只看「最近一次」用的時間,不看用了幾次:一件衣服上週剛好穿去聚會一次,就會排到最上層,但不代表它常穿。想知道常不常用,要另外記次數,這是 LFU(最不常使用)的想法,例如 LC 460。
延伸閱讀:鏈結串列實戰 裡的 LC 146 就是 LRU 快取
指數退避 失敗了就把間隔拉長
題目的訊號:這是系統設計的常見做法:請求失敗了,等一下再試;又失敗,就等更久,例如 1 秒、2 秒、4 秒、8 秒,避免一直重試把系統壓垮。
生活裡長什麼樣
- 寄信給別人沒有回覆,要隔多久再追。
- 生病或出差中斷之後重新開始練習,或者一個習慣斷了之後重新開始。
- 一直卡在同一個問題上,要不要先放下。
怎麼做
- 第一次失敗,短暫等待後再試。
- 再失敗,等待時間加倍。
- 設一個上限,到了上限就換方法,或者放手。
- 上限在開始之前就寫下來,例如「最多三次」,到了就照規則停,不要臨場再議。
例子:小明 10 月 1 日投了一份履歷,也寄信給招募負責人,一直沒有回覆。他事先定好規則:等待時間每次加倍,最多追三次。
- 第 1 次追蹤:等 3 天,10 月 4 日。
- 第 2 次追蹤:再等 6 天,10 月 10 日。
- 第 3 次追蹤:再等 12 天,10 月 22 日,這是最後一次。
- 之後就當成沒有下文,不再追,把時間放到其他職缺上。
從 10 月 1 日到 10 月 22 日一共 21 天,他只寄了 3 封追蹤信;如果每天追,21 天要寄 21 封。這比每天追問更有禮貌,也不會讓自己一直掛念。
習慣斷了,借用的是退避的另一半:先降低強度,再慢慢拉回來,而不是把間隔加倍。小明原本每天練 20 分鐘吉他,出差一週斷掉了。回來第一天,他沒有練 40 分鐘補回來,而是先練 10 分鐘;連續 3 天做到,再拉回 15 分鐘;再 3 天,回到原本的 20 分鐘。不要隔天就要求自己加倍補回來,而是先恢復到比原本更小的量,再慢慢拉回去。
AI 能幫什麼:幫你寫每一次追蹤的訊息,並記錄時間點。日期也可以請它直接算好,避免自己算錯。
小明可以這樣問:
我 10 月 1 日投了一家公司的履歷,也寄信給招募負責人,到現在還沒有回覆。請幫我排出指數退避的追蹤時間表(等 3 天、6 天、12 天,最多追三次),列出每次的日期,並寫好三封語氣逐漸收尾的追蹤信,每封不超過 80 字。第三封要讓對方知道這是最後一次聯絡。
常見誤用:沒有上限,一直追下去;或者第一次失敗就加倍處罰自己,例如習慣斷一天,隔天就要做兩倍。退避是拉長間隔、降低強度,不是加重。起點太長也不對:第一次就等一個月,對方可能早就忘了這件事。起點要短,之後再加倍。
延伸閱讀:限流器與短網址
系統設計的積木也用得上
刷題之外,系統設計的幾個基本積木在生活裡一樣好用:
- 限流器:替通知和訊息限流,例如一天只在固定兩個時段處理訊息,其他時間讓它們累積起來,一次批次處理。
- 快取:把常用的東西放在最容易拿到的地方,例如出門包、常用文件放在固定位置。
- 佇列:臨時冒出來的事一律先丟進收件匣,固定時間再處理,不要每來一件就打斷手上的事。
- 樂觀鎖:家人共用一份清單時,各自修改、送出時再檢查有沒有衝突,比事先約定誰能改更省事。
- 冪等性:同一件事做兩次結果也一樣,例如繳費前先查是不是已經繳過,避免重複付款。
例子:小明和家人共用一份週末採買清單,小明和媽媽都打開了第 7 版。小明在手機上把「牛奶 1 瓶」改成 2 瓶,同一時間媽媽在平板上把牛奶整項刪掉、加了一盒雞蛋。媽媽先存檔,清單變成第 8 版。小明送出時,清單 App 發現他改的是第 7 版,不讓他直接蓋過去,這就是樂觀鎖。接著再比對兩邊改了什麼,合併是樂觀鎖之外額外加上的一步:雞蛋只有媽媽動過,直接保留;牛奶兩邊都改過,就請小明先看過最新版本,再決定要不要把牛奶加回來,而不是直接蓋掉媽媽的修改。
清單上有牛奶 1 瓶
小明把牛奶改成 2 瓶;媽媽刪掉牛奶、加上雞蛋
版本號相同,直接存成第 8 版
他改的是第 7 版,清單已經是第 8 版,不能直接覆蓋
額外的一步:雞蛋只有媽媽改過,直接保留;牛奶兩人都改過,請小明看過再決定
AI 應該放在哪一層
前面每一節都附了小明的提問範本,它們背後是同一套流程:
這件事長得像哪一種題
預算、時間、不能接受的事
計算、列選項、寫草稿
拿已知答案的情況檢查
付款、寄出、承諾
- 你選題型,AI 跑步驟。先判斷問題是哪一種,再請 AI 做其中最花時間的那一步。如果直接問「我該怎麼辦」,得到的通常是一般性的建議。
- 把題目的限制條件告訴 AI。刷題時,限制條件決定了解法;問 AI 時也一樣,把預算、時間、不能接受的事講清楚,答案才會貼近你的情況。
- 用測資驗收。刷題要跑測試;採用 AI 的結果之前,拿一兩個你已經知道答案的情況檢查,對不上就不要全盤照用。例如小明請 AI 把三個月的記帳依類別加總,可以先拿房租對一下:房租每月固定 18,000 元,三個月應該剛好是 54,000 元,對不上就代表分類或加總出了錯。
- 不可逆的決定留給自己。付款、寄信、刪除東西、對別人做出承諾,這些步驟我一律自己按下去。這跟我在 Day 8 寫的 agent 安全邊界是同一個原則。
- 注意你貼給 AI 的資料。健康、財務、別人的個人資料,貼給雲端的 AI 之前想一下:有沒有必要、能不能先去掉可以認出身分的部分。這也是 私人 AI 集群日誌 Day 1 討論的主題。
什麼時候不要用
- 決定的代價很小時:午餐吃什麼不值得跑二分搜尋,直接用雜湊表裡的預設答案就好。
- 資料太少時:只有三天的紀錄,滑動視窗看不出任何東西,先累積再說。
- 對象是人時:關係、陪伴、照顧家人都不是最佳化問題。演算法可以幫你安排時間,但不該拿來計算值不值得。
- 規劃本身變成拖延時:拆解、排序、做表格都很有成就感,但如果花在規劃的時間比做事還多,就該停下來直接動手。
- 你在用演算法逃避感受時:分手、失業、家人生病這種時候,先處理情緒、找人說話,演算法晚一點再用。
一週練習計畫
二十個一次學不完,挑七個最常用的,一天練一個:
| 天 | 演算法 | 今天做什麼 |
|---|---|---|
| 第 1 天 | 雜湊表 | 列出三個每週重複的小決定,各寫一個預設答案 |
| 第 2 天 | Heap 與 Top-K | 早上只挑 3 件今天最重要的事,其他放進待排清單 |
| 第 3 天 | 區間合併 | 前一晚排好隔天的行程,找出最長的空檔,放隔天最重要的那件事 |
| 第 4 天 | 拓撲排序 | 挑一件卡住的大事,畫出依賴,找出入度為 0 的那件先做 |
| 第 5 天 | 樹的拆解 | 挑一個大目標,用 AI 拆成 10 個片段,刪改後放進待辦 |
| 第 6 天 | 動態規劃 | 把這週做過、以後還會再做的一件事存成模板 |
| 第 7 天 | 滑動視窗 | 把最近兩到三週的紀錄交給 AI,算每天的 7 天移動平均,看平均線往哪個方向走、哪一天偏離最多、為什麼 |
一週後回頭看:哪一個最省力?那就是最適合你、值得先養成反射動作的那一個。
帶走的東西
遇到一件事,可以依序問自己:
- 有沒有前後依賴?有的話先畫依賴圖(拓撲排序)
- 要從現狀走到目標、路線有好幾條?先寫下每一步的成本,再找總成本最低的路(最短路徑)
- 是不是太大、今天做不了?拆到葉子為止(樹的拆解)
- 有沒有幾件其實是同一件事?先合併(Union-Find)
- 是不是要從很多選項裡找可行的組合?先寫下限制來剪枝(回溯)
- 想在有限時間裡塞進最多件、每件價值差不多?照結束時間排序,每次挑最早結束又不衝突的;想讓最晚那件延誤最少,就改照截止日排序(貪婪)
- 時間或預算有限、每個選項價值不同?算組合,不要只看效率(背包問題)
- 選項一個一個出現、錯過就沒了?先看一段建立標準,再決定(最佳停止)
- 要不要試新的?看你還會在這裡待多久(探索與利用)
- 是不是在找剛好夠的量?確認有單調性,再每次砍半(二分搜尋)
- 要看的是趨勢嗎?用固定長度的視窗,不看單日(滑動視窗)
- 想知道累計到哪裡?記累計欄位(前綴和)
- 選項很多、互有勝負?先刪掉被完全比下去的(單調堆疊)
- 事情太多做不完?只留前 K 件(Heap 與 Top-K)
- 時間太零碎?把零碎的事合併成一段(區間合併)
- 以前做過類似的嗎?先找模板或預設答案(動態規劃、雜湊表)
- 想加一個新習慣?接在一個穩定的動作後面(鏈結串列)
- 空間不夠?先淘汰最久沒用的(LRU 快取)
- 一直失敗?拉長間隔、降低強度、設上限(指數退避)
每一步都再多問兩個問題:這一步交給 AI 會不會更快?結果我要怎麼驗收?
這份清單也是下一節那套統合演算法的輸入:先回答這些問題,才知道你的目標需要用到哪幾塊積木。
統合起來 一套依目標長出策略的演算法
前面二十節,每一節解決一種形狀的問題。可是真正想做成的事,很少只有一種形狀。以「半年內換工作」為例:它大到今天做不完,要用樹的拆解;步驟有先後,要用拓撲排序;時間有限,要挑先學什麼,是背包問題;會持續好幾週,每週都得擠出時間,要用 Heap 與 Top-K 和區間合併;投出去會被拒絕、要等回覆,要用指數退避。只挑一個演算法,只解決其中一塊,其他幾塊還是靠感覺。
可是也不能全部用上就好。順序錯了,演算法會互相打架:例如先用背包挑出分數最高的組合,才發現裡面有一項的前置條件根本沒被選進去。所以這一節要做的,是一套「挑演算法的演算法」:它看你的目標,決定這次需要哪幾個、照什麼順序接、衝突時聽誰的。跑完一輪,它還會把學到的存起來,下一次從更好的起點開始。
它是什麼
名稱:會長大的策略路由器,以下簡稱路由器。
一句話定義:輸入一個用白話寫的目標和現況。它先依做錯的代價和能不能反悔,決定算多仔細;再查記憶裡有沒有做過的模板;然後用十個是非題,從二十個演算法裡挑出這次需要的幾個,排好順序、填好參數。執行時每週驗收最近 4 週,把有效和無效的做法寫回記憶,所以下一次會從更好的起點開始。
幾個重點:
- 路由器不會每次把二十個全用上。答「否」的題目,對應的演算法就不出場。午餐吃什麼只會走到第一題,換工作才需要十題都問。
- 十個是非題,就是上一節「帶走的東西」那份清單濃縮成的。
- 有八個演算法會出場兩次。第一次是計畫裡的積木,例如用指數退避排追蹤信的時間;第二次是路由器自己的零件:
- 雜湊表和動態規劃:記住做過的目標和策略;
- 探索與利用:從幾種做法裡挑出有效的;
- 指數退避:讓失敗的做法先冷卻;
- 二分搜尋:調整每週時數這類參數;
- 前綴和:用實際累計校正容量;
- Union-Find 和 LRU 快取:合併相近的模板、清掉太舊的模板。
- 這就是它會「長大」的原因。它是一套讓自己越用越好的流程,不是保證最佳的公式。
做錯的代價多大、能不能反悔,決定算多仔細
做過類似的,就從模板開始改
回答十個是非題,答「是」的才叫出對應的演算法,衝突照優先順序解
排順序、填參數,同時只推前 K 件
計畫做到了沒、結果有沒有動,看最近 4 週不看單週
有效的記一次成功,失敗的冷卻,參數往中間試,存成模板
先說清楚什麼叫最佳
「最佳」永遠是對你寫下的分數和限制而言,不是對人生而言。路由器裡的方法,依保證的強弱分成三種。
精確最佳。下面四個條件同時成立時,背包問題、回溯與剪枝、最短路徑給的是精確解:
- 選項少到能全部列出。手算大約 5 個,也就是 2⁵ = 32 種組合;交給試算表或 AI 寫的小程式,大約 20 個,也就是 2²⁰ = 1,048,576 種,電腦一下就算完。
- 分數和成本你信得過。
- 硬限制寫得下來。
- 算的時候情況不會變。
二分搜尋在關係是單調、而且每次試的結果可靠時,也找得到精確的門檻。
假設下最好的規則。最佳停止的前提是「選項一個個來、錯過不回頭、只在乎最好的那一個」。在這些前提下,37% 規則選到最好選項的機率最高,但這個機率也只有約 37%。好規則不保證好結果。
夠好才是理性。選項太多、分數模糊、要試了才知道,或者代價小的時候,就用貪婪、Heap 與 Top-K、夠好門檻、探索與利用。這不是偷懶:再算下去花的力氣,比多得到的還多。epsilon-greedy 不是理論上最好的探索方法,但簡單、夠用。貪婪也只在少數題目剛好是最佳,例如 LC 435 照結束時間挑活動;生活裡多半只是夠好。
所以整套路由器不保證全域最佳,因為目標和人都會變。它保證的是下面四件事:
- 精確方法只用在真正適用的地方;
- 執行面的問題,在一個視窗內就會被看見;
- 結果面的問題,等那個做法試滿 10 次,之後的那個視窗就會被看見;
- 已知會失敗的做法,不會被不小心當成主力,只會照退避規則、用探索名額有限度地再試。
選項少到能全部列出、分數信得過、限制寫得下、算的時候情況不會變
選項一個個來、錯過不回頭、只在乎最好的那一個;37% 規則選到最好的機率最高,但也只有約 37%
選項太多、分數模糊、要試了才知道,或者代價小;先定門檻,達到就停
輸入一張目標卡
路由器的輸入是一張目標卡,六行就夠:
- 要什麼:要讓什麼變成真的,用一句白話寫,最好寫出怎樣算達成。
- 限制:每週的時間、錢、體力,以及不做的事。
- 期限:最晚哪一週要有結果。
- 在意的三件事:照順序排,之後會換算成評分的權重。
- 能不能反悔:逐步標出哪些步驟可逆、哪些不可逆。
- 以前試過什麼:有效的和失敗的都寫。這一行會預先填進路由表:冷卻中或已經停用的做法先排除;失敗過但冷卻已過的,只能佔探索名額,不當主力。
第一步 定檔位
先回答兩個問題,各給 1 到 3 分:
- 代價:做錯的話,要多久才補得回來?一週內算 1,一個月內算 2,更久算 3。
- 可逆:做了還能反悔嗎?可以算 1,部分可以算 2,不能算 3。
兩個分數相乘,就是這次要花的力氣:
| 可以反悔 1 | 部分可以 2 | 不能反悔 3 | |
|---|---|---|---|
| 代價低 1 | 輕 1 | 輕 2 | 中 3 |
| 代價中 2 | 輕 2 | 中 4 | 重 6 |
| 代價高 3 | 中 3 | 重 6 | 重 9 |
乘積是 1、2 為輕,3、4 為中,6、9 為重。每一檔的做法不同:
- 輕,也就是查表模式:只問第一題「以前做過類似的嗎」。有模板或預設答案就照做,沒有就用貪婪挑眼前最好的。5 分鐘內決定,錯了下次改。
- 中,也就是啟發模式:十題快速問一遍,以剪枝、貪婪、Top-K 為主,先求夠好;選項少到能全部列出時,一樣可以請 AI 寫一小段程式算出精確解。中檔以上都要做視窗驗收。規劃時間上限 1 小時。
- 重:十題仔細問。四個條件都成立的地方,算精確解;選項依序出現又不可逆的地方,事先寫下夠好門檻和退路;每個不可逆的步驟前,先睡一晚。規劃時間上限半天,分兩次做。
另外兩條規則:
- 規劃時間不能超過做事時間。這呼應「什麼時候不要用」那一節:規劃本身變成拖延時,就該停下來直接動手。
- 同一個目標裡,也要分步驟看。越不可逆的步驟,越要在做之前想清楚;可逆的步驟,直接做,再驗收。
這些時間上限是經驗法則,不是推導出來的數字,可以照自己的情況調整。
第二步 查記憶
這一步用的是雜湊表和動態規劃。
- 記憶庫的鍵:目標類型,例如「邊上班邊學一項技能」「求職」。這時十題還沒答,所以鍵只用目標類型。查到之後,再拿模板存的檔位和十題答案,跟這次的目標卡比對,標出不同的地方。
- 存的內容:每份模板存當時的檔位、十題答案、策略、參數、驗收方式、結果,以及上次使用的時間。這就是動態規劃的記憶表:解過的子問題存起來,下次直接拿來改。
- 查到了:從模板開始,只改這次不一樣的地方。
- 查不到:策略從空白開始,但零散的紀錄還是有用,例如某個做法以前失敗過。
- 輕檔:查到就直接照做,查不到就用貪婪挑眼前最好的,流程到這裡結束。
第三步 路由 十個是非題
每題回答「是」或「否」。答「是」就叫出對應的演算法,並填好參數;答「否」的那一列,這次不出場。每個演算法的做法,就照前面那一節。Q1 的答案直接沿用第二步查記憶的結果。
| 題 | 問題 | 答「是」時叫出 | 參數怎麼定 |
|---|---|---|---|
| Q1 | 以前做過類似的嗎? | 雜湊表(預設答案)、動態規劃(模板) | 用哪一版模板 |
| Q2 | 大到今天做不完嗎? | 樹的拆解 | 葉子要一小時內做得完 |
| Q3 | 有先後順序,或有好幾條路線能到同一個地方嗎? | 拓撲排序;有多條路線時加最短路徑 | 每一段的成本,用天、週或元算 |
| Q4 | 有幾件其實是同一件嗎? | Union-Find | 合併的標準:能不能一次處理完 |
| Q5 | 有寫得出來的硬限制嗎? | 回溯與剪枝 | 限制清單 |
| Q6 | 要在有限的時間、錢或空間裡挑嗎? | 先用單調堆疊刪掉被完全比下去的,再用背包或貪婪;限制的是空間時加 LRU 快取 | 容量;比較的面向最多 3 個 |
| Q7 | 選項一個個出現,錯過就沒了嗎? | 最佳停止 | 觀察期為總數的 37%。可以回頭、或夠好就行時要縮短。選項只有 1 到 3 個時,改用校準加夠好門檻 |
| Q8 | 結果要試了才知道,而且可以重複試嗎? | 探索與利用;在找一個剛好夠的量、而且有單調性時,改用二分搜尋 | 探索比例,見第四步;或搜尋的上下界 |
| Q9 | 要持續好幾週,每週都得擠出時間嗎? | Heap 與 Top-K、區間合併、鏈結串列;要跟別人對時間時加雙指針 | K、整塊時間的長度、錨點動作 |
| Q10 | 會失敗、被拒絕,或要等別人回應嗎? | 指數退避 | 起始間隔、倍數、最多幾次 |
| 不用問 | 中檔以上每次都做 | 滑動視窗、前綴和 | 視窗長度預設 4 週;門檻是計畫的 70%;累計計畫線 |
二十個演算法全部在表裡。「滑動視窗與雙指針」那一節的兩個做法分開放:雙指針在 Q9,滑動視窗在最後一列。最後一列不是問題:只要是中檔以上的目標,就一定要驗收,所以滑動視窗和前綴和每次都在。
| 是非題 | 查記憶 | 整理 | 選擇 | 執行 | 驗收與學習 |
|---|---|---|---|---|---|
| Q1 做過類似的 | 雜湊表動態規劃 | ||||
| Q2 今天做不完 | 樹的拆解 | ||||
| Q3 有先後或多條路 | 拓撲排序最短路徑 | ||||
| Q4 其實是同一件 | Union-Find | ||||
| Q5 有硬限制 | 回溯與剪枝 | ||||
| Q6 資源有限要挑 | 單調堆疊背包問題貪婪 | LRU 快取 | |||
| Q7 錯過就沒了 | 最佳停止 | ||||
| Q8 試了才知道 | 探索與利用二分搜尋 | ||||
| Q9 要持續數週 | Heap 與 Top-K區間合併鏈結串列雙指針 | ||||
| Q10 會失敗或要等 | 指數退避 | ||||
| 每次都要驗收 | 滑動視窗前綴和 | ||||
| 路由器自己用 | 雜湊表動態規劃探索與利用指數退避二分搜尋前綴和Union-FindLRU 快取 |
衝突時誰優先
叫出來的演算法,有時會給出不同的答案。這時照下面六層的順序,上面的永遠勝過下面的:
- 硬限制與不可逆:寫下的限制先剪枝;不可逆的一步,一定由人做。
- 依賴順序:前置條件還沒完成的選項,不拿來比。
- 實際回饋:最近 4 週的真實數字,勝過當初的估計、分數和模板。
- 能算精確就算:選項少、分數可信、不是輕檔時,精確解勝過近似。
- 時間窗口:錯過就沒了的,用最佳停止或夠好門檻;能重複試的,才用探索。
- 預設與模板:只是第一個猜測。
常見的衝突這樣解:
- 背包 vs 貪婪:選項少、分數可信、檔位是中或重時,用背包。其他情況先用單調堆疊縮小選項,再用貪婪。
- 最佳停止 vs 探索與利用:一次性、錯過就回不去的,用最佳停止;可以重複試的,用探索與利用。
- 二分搜尋 vs 探索:在找一個「量」、而且有單調性,用二分;在找「哪一個」,用探索。
- Union-Find vs 拓撲排序:兩件事併成一件時,不能讓其中一件跳過它原本要等的事。依賴是第 2 層,勝過合併。
- 背包 vs 依賴:背包選出的組合,前置條件要全都在裡面,否則被第 2 層剪掉。
- 模板 vs 回饋:模板說每週 10 小時,實際只做到 6 小時,就聽實際的。第 3 層勝過第 6 層。
- 指數退避 vs 期限:退避的間隔加起來,不能超過決策的期限。
- Top-K vs 葉子很多:拆出來的葉子先放進待排清單,同時只推進 K 件。
第四步 組裝並執行
- 用拓撲排序把所有步驟排好。
- 填參數:葉子大小、K、容量、門檻、探索比例、視窗長度、退避間隔。探索比例預設 20%,也就是探索與利用那一節的「五次裡試一次」;這個階段只剩最後四分之一時,降到 10%;不可逆的步驟是 0%,不拿來實驗。
- 最後檢查兩件事:總時數不超過可用的時數;每一條硬限制都寫進了計畫。
- 每週只推進前 K 件,其他的留在待排清單。
- 遇到付款、簽約、寄出、接受 offer、提離職,流程停下來,交給人。
第五步 驗收 兩種訊號
每週看一次最近 4 週,看兩種訊號:
- 執行訊號:實際做到的 ÷ 計畫要做的,例如時數、投遞份數。
- 結果訊號:實際成果 ÷ 計畫的成果,例如面試數。
兩種都用滑動視窗看最近 4 週,不看單週;再用前綴和,把實際累計跟計畫線放在一起,看超前還是落後。
分開看兩種訊號,是為了知道該跳回哪一步:
| 結果有動 | 結果沒動 | |
|---|---|---|
| 計畫做到了 | 繼續,記一次成功 | 做法錯了:退避這個做法,回第三步,換證據最好的下一個 |
| 計畫沒做到 | 方向對、成本估錯:用實際數字重估,回第四步重排;做不到的那個排法也記一次失敗 | 先修執行,回第四步重排;做不到的那個排法也記一次失敗。計畫沒照做時,結果訊號說明不了什麼 |
另外幾條規則:
- 目標或限制變了:回第一步,重新定檔位。
- 門檻:低於計畫的 70% 就觸發。重新組裝之後,視窗從零開始算。
- 樣本:執行的資料每週都有,看得快;結果的資料少,要等同一個做法試了 10 次以上才判斷。試太少就下結論,跟「什麼時候不要用」那一節說的「資料太少」是同一種錯。
- 超標:結果連續兩個視窗超過 130%,就把多出來的時間還給別的事;執行做到 100% 但還沒到想要的量,就用二分搜尋往上試。兩條可能同時成立:結果已經連續兩個視窗超過 130% 時,先把多出來的時間還給別的事,不再往上試;想要的量也改成目前的量。
- 70%、130%、10 次,都是可以調整的預設值。
第六步 學習 它怎麼越用越好
每跑完一輪驗收,路由器做六件事。這裡用到的演算法,跟計畫裡用的是同一批,只是這次用在路由器自己身上:
- 模板記憶,用雜湊表加動態規劃:把這次的十題答案、參數、驗收方式和結果存成模板。
- 路由統計,用探索與利用:每個做法記兩個數字,試過幾次、成功幾次。證據最好的當主力,保留 20% 的名額試別的。樣本少的時候數字會騙人,所以要有「至少試 10 次才判斷」的規則。
- 冷卻失敗的做法,用指數退避:
- 第 1 次失敗:冷卻 2 週,回來後只佔探索名額;
- 第 2 次失敗:冷卻 4 週;
- 第 3 次失敗:這類目標不再用它,並寫進記憶。
- 參數調校,用二分搜尋:像每週時數這種量,新目標 =(確定做得到的最高量 + 確定做不到的最低量)÷ 2,差距在 1 個單位以內就停。前提是單調性:目標越高,越難做到。
- 成本校正,用前綴和:容量用實際累計的時數算,不用計畫值。
- 記憶修剪,用 Union-Find 加 LRU 快取:相近的模板合併成一份;超過 20 份時,刪掉最久沒用的那一份,避免拿太舊的模板套新情況。
AI 和人各管哪一段
這一段接的是前面「AI 應該放在哪一層」:AI 跑步驟,人決定題目、驗收結果、按下最後一步。放進路由器的六個步驟,分工是這樣:
| 階段 | AI 做 | 人做 |
|---|---|---|
| 定檔位 | 列出哪些步驟不可逆,找出藏著的不可逆 | 決定代價和檔位,決定花多少時間 |
| 查記憶 | 從貼上的模板裡找最像的 | 確認是不是真的相似 |
| 路由 | 照目標卡先答十題,標出沒把握的題 | 改正答案,寫下硬限制和分數 |
| 組裝並執行 | 寫小程式窮舉組合、算背包、畫依賴圖、排時程、寫草稿和追蹤信 | 從前幾名裡挑一個;按下付款、寄出、簽約、接受、提離職 |
| 驗收 | 算視窗平均和累計,對照每天的備註找原因 | 判斷這個數字還能不能代表目標 |
| 學習 | 更新路由表和模板 | 核准改動,決定什麼算成功,決定要不要延期 |
人永遠要保留五件事:
- 什麼重要,也就是分數;
- 硬限制;
- 不可逆的最後一步;
- 停止或放棄的決定;
- 牽涉到別人的事。
整套流程的虛擬碼
下面把六個步驟寫成虛擬碼。不會寫程式也能讀:一行一個動作,「←」的意思是「設成」,「//」後面是說明。
策略路由器(目標卡)
// 第一步 定檔位
代價 ← 問「做錯的話,要多久才補得回來?」 // 一週內=1,一個月內=2,更久=3
可逆 ← 問「做了之後還能反悔嗎?」 // 可以=1,部分可以=2,不能=3
力氣 ← 代價 × 可逆 // 1–2 輕,3–4 中,6–9 重
規劃時間上限 ← 輕 5 分鐘、中 1 小時、重 半天分兩次
// 第二步 查記憶
鍵 ← 目標類型 // 這時十題還沒答
模板 ← 記憶庫裡同一鍵、最近用過的那一份
如果 有模板:策略 ← 模板,拿模板存的檔位和十題答案跟目標卡比對,標出不同的地方
否則:策略 ← 空白
如果 力氣是輕:有模板或預設答案就照做,沒有就用貪婪挑眼前最好的;結束
// 第三步 路由
Q1 ← 第二步查記憶的結果
對 Q1 到 Q10 每一題:
如果 答案是「是」:把路由表裡這一題的演算法加進候選
加入 滑動視窗 和 前綴和 // 中檔以上每次都要驗收
拿掉 冷卻中或已經不再用的做法
失敗過、冷卻已過的做法:只能放進探索名額,不當主力
如果 兩個候選衝突:照優先順序,留下排前面的
對每一個要做的選擇:
如果 精確解的四個條件都成立:算精確解 // 背包、回溯、最短路徑
否則如果 選項一個個來、不能回頭:寫下夠好門檻和退路
否則:用貪婪或 Top-K,先求夠好
// 第四步 組裝並執行
依拓撲排序排好步驟
填參數:葉子大小、K、容量、門檻、探索比例、視窗長度、退避間隔
探索比例 ← 可逆 20%;這個階段只剩最後四分之一時 10%;不可逆 0%
每週只推進前 K 件
遇到付款、簽約、寄出、接受、離職:停下來,交給人
// 第五步 驗收,每週一次,看最近 4 週
執行訊號 ← 實際做到的 ÷ 計畫要做的
結果訊號 ← 實際成果 ÷ 計畫的成果
如果 目標或限制變了:
回第一步
否則如果 執行訊號 < 70%:
用實際數字重估成本和容量
如果 要調的是時數這類的量:新目標 ← 二分(做得到的最高量, 做不到的最低量)
如果 出問題的是某個排法:退避(這個排法)
回第四步,只重排出問題的那一塊
否則如果 結果訊號 < 70% 而且 這個做法已經試了 10 次以上:
退避(這個做法)
回第三步,換路由表裡證據最好的下一個做法
否則如果 結果訊號連續兩個視窗 > 130%:
把多出來的時間還給別的事
想要的量 ← 目前的量,不再往上試
否則如果 執行訊號 ≥ 100% 而且 還沒到想要的量:
新目標 ← 二分(做得到的最高量, 做不到的最低量) // 差距 1 單位以內就停
// 試不到 10 次的做法先不判斷,繼續收資料
// 重新組裝之後,視窗從零開始算
// 第六步 學習
每個用過的做法:試過次數 加 1;有效就 成功次數 加 1
記憶庫.存(鍵, 檔位, 十題答案, 策略, 參數, 驗收方式, 結果)
相近的模板合併成一份
記憶庫超過 20 份時,刪掉最久沒用的那一份
回到第五步,直到目標達成或期限到;期限要不要延,由人決定
二分(低, 高):
回傳 (低 + 高)÷ 2
退避(做法):
做法.失敗次數 加 1
失敗 1 次:冷卻 2 週,回來後只佔探索名額
失敗 2 次:冷卻 4 週
失敗 3 次:這類目標不再用它,寫進記憶
完整例子 小明半年內轉職前端
最短路徑那一節,小明比較過從客服轉 UX 設計師的路線。後來架個人小網站的那幾週,他發現自己最喜歡的是寫程式的部分,決定把目標換成網頁前端。目標換了,策略就要重新長一次。下面是路由器從第 0 週跑到第 26 週的完整過程。全程只用週次,數字都是為了示範而設定的。
目標卡
| 欄位 | 小明寫的 |
|---|---|
| 要什麼 | 26 週內,從現在的客服工作換到一份初階網頁前端工作,以「接受 offer」為終點 |
| 限制 | 準備期間不離職;每週最多 10 小時 |
| 期限 | 第 26 週 |
| 在意的三件事 | 1 工作內容是做網頁;2 單程通勤 40 分鐘內;3 有人帶。換算成評分:40 + 30 + 30 = 100 分 |
| 能不能反悔 | 學習、投遞、面試都可逆;接受 offer、提離職不可逆 |
| 以前試過什麼 | 去年試過早上 6 點起床寫程式,兩週就停了;求職時用過「等 3、6、12 天,最多追三次」的追蹤規則,就是指數退避那一節的做法 |
定檔位
- 代價 3:做錯要半年以上才補得回來。
- 可逆 2:投遞、面試可逆,接受 offer 和提離職不可逆,所以是部分可逆。
- 3 × 2 = 6,重檔:十題全部仔細問,規劃時間半天、分兩次做,接受 offer 前先睡一晚。
同一個目標裡再分步驟看:挑要學什麼,選項少、分數自己給得出來,可以算精確解;挑工作是錯過就沒了的,用規則加門檻;每天晚上先做哪一片這種小事,直接用雜湊表裡的預設答案。
查記憶
「邊上班邊轉職」沒有模板,策略從空白開始。不過記憶裡有兩筆零散的紀錄:追蹤規則可以直接用;「早上 6 點起床」去年失敗 1 次,冷卻早就過了,照規則只能佔探索名額,不當主力;小明這次不把探索名額給它。
十題的答案
| 題 | 小明的答案 | 叫出 | 參數 |
|---|---|---|---|
| Q1 | 一半是 | 雜湊表 | 追蹤規則 3、6、12 天;「早上 6 點起床」失敗 1 次,只能佔探索名額,不當主力 |
| Q2 | 是 | 樹的拆解 | 三枝:技能、作品集、求職;每片葉子一小時內 |
| Q3 | 是 | 拓撲排序、最短路徑 | 排出的順序:HTML 與 CSS → JavaScript → 作品集網站 → Git 與部署 → 履歷 → 投遞 → 面試 → offer。比較三條路線到「可以投遞」要幾週:自學 12 週(基礎 7、作品集 4、緩衝 1);線上課程 10 + 作品集 4 = 14 週;夜間課程 26 週。選自學。內部轉調走不通,因為公司的工程部門今年沒有開初階前端的缺 |
| Q4 | 是 | Union-Find | 作品集網站、履歷上的專案段落、面試要講的故事併成一件;樹的拆解那一節他想架的個人小網站,也併進來當作品集網站 |
| Q5 | 是 | 回溯與剪枝 | 不離職;每週 ≤10 小時;職缺必須是前端;通勤 ≤40 分鐘 |
| Q6 | 是,限制的是時間 | 背包;求職時加單調堆疊 | 容量 12 週 × 10 小時 = 120 小時;空間沒有限制,不用 LRU |
| Q7 | 是,職缺和 offer | 最佳停止,改成校準加夠好門檻 | 預計 offer 只有 1 到 3 個;前 3 場面試只用來校準分數 |
| Q8 | 是,投遞管道 | 探索與利用 | 每週 5 份裡 1 份試別的管道,20%;開始時沒有要找的量,二分搜尋先不出場 |
| Q9 | 是 | Heap 與 Top-K、區間合併、鏈結串列、雙指針 | K = 3;整塊時間是平日四晚各 1.5 小時 + 週六 4 小時 = 10 小時;錨點「到家 → 打開筆電」;求職期用雙指針對齊小華的空檔,排模擬面試 |
| Q10 | 是 | 指數退避 | 追蹤 3、6、12 天,最多三次 |
| 不用問 | — | 滑動視窗、前綴和 | 視窗 4 週;門檻 70% × 10 = 7 小時/週;累計計畫線每週加 10 小時 |
這次沒有出場的有四個:動態規劃,因為沒有模板可以改;貪婪,因為學習項目少到能算精確解,求職用的是 Top-K;LRU 快取,因為沒有空間限制;二分搜尋,因為開始時沒有要找的量。後面會看到,其中三個被路由器拿去用在自己身上:二分搜尋調每週時數,動態規劃把這次存成模板,LRU 快取在模板太多時清掉太舊的。
背包,精確解
小明列出 7 個想學的項目,各自估了時數、給了分數。依賴關係是:JavaScript 要先會 HTML 與 CSS;兩個作品集網站都要先會 HTML 與 CSS 和 JavaScript;React 要先會 JavaScript;Git 與部署、演算法練習不用等別的。
| 選項 | 時數 | 小明給的分數 |
|---|---|---|
| HTML 與 CSS | 30 | 9 |
| JavaScript | 40 | 10 |
| 第一個作品集網站 | 30 | 9 |
| 第二個作品集網站 | 35 | 8 |
| React 入門 | 25 | 6 |
| 演算法練習 | 30 | 4 |
| Git 與部署 | 10 | 7 |
- 7 個選項各自選或不選,一共 2⁷ = 128 種組合。小明請 AI 寫一小段程式(或試算表公式)把 128 種組合全部算出來,再自己抽幾組驗算。
- 最佳解:HTML 與 CSS + JavaScript + 第一個網站 + Git 與部署,共 110 小時、35 分,而且是唯一的最佳解。
- 五項一定放不下:最小的五項加起來是 10 + 25 + 30 + 30 + 30 = 125,超過 120。
- 次佳 34 分有兩組,都是 115 小時:HTML 與 CSS + JavaScript + 第二個網站 + Git;JavaScript + 第一個網站 + 第二個網站 + Git。後者沒有 HTML 與 CSS,被第 2 層的依賴順序剪掉。
- 120 小時用掉 110 小時,剩下的 10 小時當緩衝。
這是對小明自己給的分數而言的最佳解。分數換了,答案也會跟著換。
| 1–2 | 3–4 | 5–6 | 7–8 | 9–10 | 11–12 | 13–14 | 15–16 | 17–18 | 19–20 | 21–22 | 23–24 | 25–26 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| HTML 與 CSS | 重 | 中 | |||||||||||
| JavaScript | 中 | 重 | 中 | ||||||||||
| 作品集網站 | 中 | 重 | |||||||||||
| Git 與部署 | 中 | ||||||||||||
| 履歷與緩衝 | 中 | ||||||||||||
| 投遞與面試 | 重 | 重 | 重 | 重 | 重 | 重 | |||||||
| 追蹤回覆 | 輕 | 輕 | 輕 | 輕 | 輕 | 輕 | |||||||
| 緩衝 | 輕 |
第一次回饋:執行訊號
第 4 週,第一次有完整 4 週的資料。前 4 週實際做到的時數:
| 週 | 平日 | 週六 | 合計 |
|---|---|---|---|
| 1 | 一 1.5、二 1.5、三 1.5、四 0.5 = 5 | 4 | 9 |
| 2 | 一 1.5、二 0.5 = 2 | 4 | 6 |
| 3 | 一 1.5 | 3.5 | 5 |
| 4 | 0 | 4 | 4 |
- 4 週共 24 小時,平均每週 6.0 小時,是計畫的 60%,低於門檻 7 小時。
- 前綴和:實際累計 24 小時,計畫線是 40 小時,落後 16 小時。
- 拆開看:平日只做到 8.5 小時,計畫是 24 小時,約 35%;週六做到 15.5 小時,計畫是 16 小時,約 97%。
只有平日這一塊出問題。這是「計畫沒做到」,不是「做到了卻沒效」,所以回第四步,只重排平日這一塊。AI 對照每天的備註,發現沒做到的晚上,多半是一到家就躺到床上滑手機,之後就不想動了。這跟鏈結串列那一節熬夜的環,是同一個入口:躺在床上滑手機。
重排平日這一塊
- 「平日四晚」記失敗 1 次,進入冷卻。
- 「早上 6 點」去年失敗過 1 次,只能佔探索名額,不能拿來當新的主力排法。
- 參考週六的 97%:整塊、固定的時段比較撐得住。改用區間合併加鏈結串列,錨點從「到家」改成「下班走出公司」:週二、週四下班後,在公司旁的咖啡店各 1 小時;週六 4 小時;週日 2 小時。
- 新的每週目標用二分搜尋:以四週平均算,做得到的 6 小時和做不到的 10 小時,中間是 8 小時,1 + 1 + 4 + 2 剛好 8。
- 新門檻:70% × 8 = 5.6 小時。
容量也要重估
這是第 3 層「實際回饋」勝過當初的估計。
- AI 算出:以每週 8 小時計,還差 110 − 24 = 86 小時,86 ÷ 8 = 10.75,要再 11 週,學習期會拉到第 15 週。
- AI 列出兩個解法:
- 延長:學習的 110 小時原本在第 11 週學完,現在要到第 15 週;第 12 週那段寫履歷的緩衝,順延到學完之後的第 16 週,投遞從第 13 週延到第 17 週。
- 不延長,第 13 週照樣開始投遞:第 1 到 12 週的容量變成 24 + 8 × 8 = 88 小時,重算背包。考慮依賴後,最佳是 HTML 與 CSS + JavaScript + Git,80 小時、26 分,剩下 8 小時寫履歷,但作品集網站被擠掉了。
- 小明選第 1 個。作品集網站是求職階段的入場券,而他當初打的分數沒有反映這一點。這正是要由人判斷的地方:演算法照分數算,分數漏掉的東西要人來補。
第 5 到 8 週
- 每週 8、7、8、9 小時,共 32 小時,平均 8.0。第 6 週週四沒做到,第 8 週週日多做了 1 小時。
- 執行訊號 100%。累計 24 + 32 = 56 小時,剛好在新的計畫線上:24 + 4 × 8 = 56。
- 已經做到 100%,但還沒到原本想要的 10 小時,所以用二分往上試:(8 + 10) ÷ 2 = 9。週日從 2 小時加到 3 小時,新門檻是 70% × 9 = 6.3 小時。
- 還差 110 − 56 = 54 小時,54 ÷ 9 = 6 週,學習期縮回到第 14 週結束,寫履歷和開始投遞都提早到第 15 週。
第 9 到 14 週
- 每週 9、9、8、10、9、9 小時,共 54 小時,第 14 週累計剛好 110 小時。
- 第 12 週驗收第 9 到 12 週:9 + 9 + 8 + 10 = 36,平均 9,執行 100%。做得到的 9 和做不到的 10 只差 1 小時,停止往上試。
- 第 12 週的 10 小時只是單週,10 小時的四週平均沒有做到過,所以上界仍是 10。不過 10 小時是在舊排法下做不到的,新排法沒試過;先停在 9,之後如果想再試 10,就用探索名額試一個視窗。每週 9 小時是目前的答案。
- 第 14 週學完。履歷用第 15 週的 9 小時寫,那週先只投 1 份,其他 4 份補在第 16 到 18 週,所以視窗 1 還是 20 份。
| 第1週 | 第2週 | 第3週 | 第4週 | 第5週 | 第6週 | 第7週 | 第8週 | |
|---|---|---|---|---|---|---|---|---|
| 週一晚上 | 完成 | 完成 | 完成 | 沒做 | ||||
| 週二晚上 | 完成 | 部分 | 沒做 | 沒做 | 完成 | 完成 | 完成 | 完成 |
| 週三晚上 | 完成 | 沒做 | 沒做 | 沒做 | ||||
| 週四晚上 | 部分 | 沒做 | 沒做 | 沒做 | 完成 | 沒做 | 完成 | 完成 |
| 週六 | 完成 | 完成 | 部分 | 完成 | 完成 | 完成 | 完成 | 完成 |
| 週日 | 完成 | 完成 | 完成 | 完成 |
第二次回饋:結果訊號,第 15 到 26 週求職
每週的做法:
- 用硬限制剪枝:不是前端的、單程通勤超過 40 分鐘的職缺,直接刪掉;
- 用單調堆疊,刪掉三個面向都被比下去的職缺;
- 依分數挑前 5 名投遞,也就是 Top-K。
管道和門檻:
- 主力:人力銀行,每週 4 份。
- 探索:直接寫信給團隊並附上作品集,每週 1 份,20%。
- 結果門檻:每 4 週 20 份,換到 2 個面試,也就是 10%。這個數字是小明猜的,沒有模板可以參考。
- 每場面試前,小明用雙指針對齊自己和小華的空檔,約一次模擬面試;投遞或面試後沒有回音,就照追蹤規則等 3、6、12 天再追。
| 視窗 | 投遞 | 面試 | 達成 |
|---|---|---|---|
| 1,第 15–18 週 | 人力銀行 16、直接寫信 4 = 20 | 0 + 1 = 1 | 1 ÷ 2 = 50% |
| 2,第 19–22 週 | 直接寫信 16、小華介紹 2、人力銀行 2 = 20 | 3 + 1 + 0 = 4 | 4 ÷ 2 = 200% |
視窗 1
- 執行訊號:計畫 20 份,投了 20 份,100%。
- 結果訊號:1 個面試,計畫 2 個,50%,低於 70%。
- 計畫做到了、結果沒動,表示做法錯了,回第三步。
- 人力銀行已經試了 16 次,超過 10 次,可以判斷:記失敗 1 次,冷卻 2 週,回來後只佔探索名額。
- 直接寫信只試了 4 次、1 個面試,樣本還小,但證據最好,所以升為主力,每週 4 份。
視窗 2
- 重新組裝之後,視窗從第 19 週重新算起。探索名額的安排:第 19、20 週給新管道「小華介紹」;第 21、22 週給冷卻結束的人力銀行。
- 結果訊號 200%。只有一個視窗超過 130%,所以先不動。
- 累計:直接寫信 20 份、4 個面試,20%;小華介紹 2 份、1 個面試,樣本太小,留在探索名額;人力銀行 18 份、0 個面試,下一個視窗如果還是 0,就是第 2 次失敗,冷卻 4 週。
offer 怎麼選
- 不用 37% 規則。原因有三:預計 offer 只有 1 到 3 個;有時可以請對方等幾天,不完全是錯過就沒了;而且夠好就可以,不一定要最好。這正是最佳停止那一節「常見誤用」提醒過的情況。
- 每場面試後,小明照目標卡上的三件事,替那份工作打分數,滿分 100。前 3 場只用來校準:第 18 週 61 分、第 20 週 74 分、第 21 週 68 分。
- 門檻:硬限制全部通過,而且分數 ≥ 74,也就是前 3 場的最高分。
- 退路:到第 24 週結束還沒有過門檻的 offer,門檻降到 70。
- 第 22 週又有兩場面試,71 分和 80 分。繼續面試是可逆的,所以 71 分那家不用急著刷掉;門檻只用在接受 offer 的那一刻。
- 第 24 週,80 分那家給了 offer:80 ≥ 74,硬限制全部通過。路由器只說「這符合你寫下的規則」。
- 小明睡一晚後,自己決定接受,離期限還有 2 週。提離職照合約的通知期另外處理,不在這個目標內。
存回記憶
- 「邊上班邊學一項技能」模板:整塊時段比零碎的平日晚上可靠;從做得到的量開始,用二分往上試;容量用實際時數算。
- 「求職」模板:管道順序是直接寫信附作品集 > 小華介紹 > 人力銀行;視窗 4 週,結果門檻 10%;追蹤 3、6、12 天。
前 4 週平日只做到 8.5 小時,計畫是 24 小時,約 35%;記失敗 1 次,冷卻 2 週後只能當探索選項
去年失敗 1 次,冷卻早就過了,照規則只能當探索選項;這次沒有拿探索名額試它
二分搜尋:做到 6、失敗 10,先試中間的 8;做到了,再試 8 和 10 中間的 9
110 小時從第 11 週學完延到第 14 週學完;寫履歷順延到第 15 週,同一週開始投遞
16 份 0 個面試,冷卻 2 週,回來後每週只投 1 份
累計 20 份 4 個面試,20%
學技能那份存時段和起始時數的規則,求職那份存管道順序、驗收門檻和追蹤規則
下一個目標怎麼長得更快
- 小明想在半年後和小華去日本玩之前,把日文學到能點餐、問路的程度,打算報名一期日文課。
- 定檔位:代價 2 × 可逆 2(課程費要先付一期)= 4,中檔。
- Q1 命中「邊上班邊學一項技能」。模板是在重檔存的,這次是中檔,這一點標成不同;時段規則直接沿用:週二、週四各 1 小時 + 週六 2 小時 = 4 小時。
- 「平日四晚」已記失敗 1 次,只能佔探索名額,不會被當成主力排進去。這次規劃只花 20 分鐘,中檔的上限是 1 小時。
這不保證小明拿到 offer。它保證的是他每四週就知道計畫有沒有照做;方向對不對,等每個做法試滿 10 次就知道,而不是到第六個月才發現。
AI 能幫什麼:照目標卡先答十題、算背包和容量、每週算兩種訊號、更新路由表;分數、硬限制和不可逆的那一步留給人。
小明可以這樣問:
以下是我的目標卡、十個是非題的答案,和我的路由表(哪些做法試過幾次、成功幾次、冷卻到哪一週)。請先判斷每一步該用查表、啟發還是精確解,再組出一份策略:用哪些演算法、什麼順序、每個參數填多少,以及每週要記哪兩種數字、門檻是多少。沒把握的題請標出來。付款、簽約、接受 offer、提離職這種不能反悔的步驟,請標出來留給我決定,不要替我決定。
這套演算法的限制
- 輸出只會跟輸入的分數和限制一樣好。分數錯了,最佳解也跟著錯,就像小明一開始給作品集網站的分數,沒有反映它是求職的入場券。
- 十個是非題是經驗法則,遇到新類型的問題,可能要再加題。
- 70%、130%、至少 10 次、20 份模板、冷卻 2 週和 4 週,都是可以調整的預設值,不是定律。
- 樣本太少時,例如只有一兩週的資料,或某個做法試不到 10 次,不要急著判斷。這跟「什麼時候不要用」那一節說的「資料太少時」是同一個原則。
- 數字一旦變成目標,就可能被灌水。要定期確認,每週的時數還代表真的進度,而不是坐在咖啡店滑手機。
- 人際關係、陪伴、照顧家人,不是它該處理的。維護表格的時間比做事還長時,就退回查表模式。這兩點都呼應「什麼時候不要用」那一節。
- 把紀錄貼給雲端 AI 之前,先拿掉可以認出身分的細節,例如公司名稱和面試官的名字。
延伸閱讀
這篇的很多想法,在 Brian Christian 和 Tom Griffiths 的《Algorithms to Live By》裡有更完整的討論,特別是最佳停止、探索與利用、快取和排程,推薦想深入的人讀讀看。這篇跟那本書的差別,是從刷題的題型出發,並把 AI 放進每一個步驟裡。
刷題的時候,我們練的是在 45 分鐘內看出題目的形狀。生活沒有時間限制,但同樣的眼力,能讓每天的決定少花一點力氣,把精神留給真正重要的事。