cswork / libraryOpen practice workspace

Articles

LeetCode 是什麼?新手從第一題、測試到解答檢討的使用指南

LeetCode 是什麼?從讀題、選語言與函式模板開始,分清 Run 和 Submit,用反例找錯,再關掉解答獨立重寫。附原創小練習與下一題的選擇方法。

LeetCode 是讓你閱讀程式題、撰寫解法,再交給線上評測系統檢查的練習平台。對新手而言,第一個目標不是刷完一份題單,而是完整走過一次:理解題目、寫出可執行的程式、設計測試、讀懂提交結果,最後在不看解答的情況下重寫。

如果你一打開題目就卡住,不代表你不適合寫程式。你可能還沒分清楚「演算法不會」、「語法不熟」與「不知道平台要我交什麼」。這三種問題需要不同的處理方式。本文從第一次操作與解答檢討出發,不要求你已經理解資料結構題單。

完成這個流程後。

LeetCode 能練什麼?先分清楚題目、程式與評測

把一題想成三個部分。題目描述告訴你要完成的工作;編輯器讓你用選定語言實作;評測系統則用輸入檢查你的結果。你要交的是符合規格的程式,不是一段看起來合理的說明。

LeetCode 官方入門說明介紹語言模板、執行測試、提交及查看結果。這份說明更新於 2022 年,適合理解基本概念;按鈕位置與版面請以你目前看到的介面為準,不必拿舊截圖逐像素比對。

刷題能幫助你練習把條件轉成程式、比較不同解法,並發現邊界錯誤。但線上評測不等於完整面試。它不會自動證明你能解釋取捨、理解陌生專案,或處理需求變動。因此,先把它當成實作與驗證工具,不要把完成題數直接換算成錄取機率。

第一次練習也不用急著付款。先用你目前可存取的題目確認流程是否適合自己;遇到受限內容,再判斷那項功能是不是你真正需要的。本文不假設任何付費功能、目前價格或所有題目都可免費使用。

第一題怎麼選?選你能說出規格的題目

先選一種已經會寫基本變數、迴圈與函式的語言。若你完全不懂語法,先補一個小型程式練習,比反覆切換 Python、Java、C++ 更有效。語言不是愈多愈好;第一題需要的是能看懂錯誤訊息並完成修改。

挑題時先看輸入、輸出、範例與限制,不要只看 Easy 標籤。標籤無法告訴你是否學過該題需要的概念。對入門者,單次陣列掃描或簡單字串處理通常比需要陌生樹結構的題目容易開始,這是本文的選題建議,不是平台官方排序。

讀完後,先用自己的話補齊四句話:「輸入是什麼」、「我要回傳什麼」、「找不到時怎麼辦」、「有哪些大小或數值限制」。如果其中一句說不出來,先回到題目,不要急著找最佳解。

中文翻譯或輔助工具可以幫你理解文字,但仍要核對比較符號、索引與順序。把 strictly greater 翻成「大於」後,不能寫成「大於等於」;把 index 翻成位置後,仍要確認位置從 0 還是 1 開始。能解釋這些詞,比記住整段題目更重要。

用一個原創小練習,走過讀題到寫程式

下面是本文自製的教學練習,不是 LeetCode 原題:給定整數陣列 nums 與整數 limit,回傳第一個「嚴格大於 limit」的元素索引。索引從 0 開始;若沒有符合元素,回傳 -1。這個練習允許空陣列。

例如 nums = [2, 7, 4]、limit = 5。先看 2,不符合;再看 7,符合,所以答案是索引 1,不是數值 7,也不是第幾個符合元素的數量。後面的 4 不必再決定答案。

這時可以先寫出最直接的解法,而不是搜尋一個看起來更高級的技巧:

def first_above(nums, limit):
    for index, value in enumerate(nums):
        if value > limit:
            return index
    return -1

enumerate 同時提供索引與數值;return 把結果交回呼叫者,並結束函式。找不到時,迴圈結束後回傳 -1。它不會把陣列排序,因為排序會改變「第一個」在原始輸入中的意義。

逐步檢查時,可以寫下每次比較:2 > 5 為假,7 > 5 為真,於是回傳 1。這叫做手動追蹤。即使程式只有幾行,追蹤也能確認你回傳的是索引,不是元素。

時間複雜度最壞為 O(n):沒有符合元素時,要看完全部 n 個值。額外空間為 O(1):除迴圈變數外,不建立隨輸入增大的新資料結構。先能說出「為什麼」,再記住符號;不用把複雜度當成咒語。

Run 與 Submit:樣例通過,不等於整題正確

依官方入門說明,執行程式可用目前的測試輸入檢查結果,提交則進入題目的評測。不要把一次 Run 成功理解成所有可能輸入都已通過。你自己加的案例很有價值,但它仍然只測你選的情況。官方說明

先看編輯器給你的函式名稱、參數與回傳型別。若模板要求回傳整數,就應該回傳整數;在畫面印出 1 不一定等於把 1 回傳給評測程式。也不要任意改掉模板的類別或方法名稱,再期待系統知道你換了入口。

自訂測試的輸入格式也依目前題目介面而定。有些介面要求每個參數分開填寫;不能假設把整段 Python 函式呼叫貼進輸入框就能執行。先模仿已提供的測試格式,確認輸入被正確解析。

修改後先 Run,查看實際值與預期值,再 Submit。若提交失敗,不要只重按提交,也不要在沒有新證據的情況下亂改多個地方。把最小失敗案例帶回本地或自訂測試,通常能縮小原因。

測試要針對假設,不是換幾組好看的數字

假設你把上面程式誤寫成 value >= limit,第一個範例仍會通過。但 [5] 配上 limit = 5 就會錯。這個案例的價值不在於數字特別,而在於它把兩種規則分開了。

自製測試預期結果要抓的錯誤
[2, 7, 4],limit 51回傳索引而不是元素值
[5],limit 5-1把嚴格大於誤寫成大於等於
[],limit 5-1沒有元素時仍有明確結果
[7, 2, 8],limit 50回傳第一個,而不是最後一個
[-3, -1],limit -21不假設輸入必須為正數

這些案例只適用於這個自製練習的規格。正式題目若保證陣列非空,就不必為空陣列額外發明規則;若要求回傳所有位置,也不能沿用找到第一筆就結束的做法。測試要對準題目,不是套一張固定清單。

請先手算預期值,再執行。若你用自己的程式輸出當作「標準答案」,錯誤可能會自我確認。新手不需要一開始就建立大型測試框架;五個能說明目的的案例,比五十個沒看懂的隨機輸入更有用。

看懂提交結果:先分類,再修正

Accepted 表示該次提交通過題目評測;它不是你已經理解解法的證明。Wrong Answer 則表示結果不符合預期,要從規格、比較條件、索引、順序與資料狀態找原因。

如果是語法或編譯問題,先讀第一個有用的錯誤位置,檢查括號、縮排、名稱與型別。Runtime Error 是執行途中出錯,常見的自我檢查包括越界、空值,以及某條分支沒有處理到的資料。這些是診斷方向,不能只憑狀態名稱就斷定唯一原因。

Time Limit Exceeded 時,先查迴圈能否結束,再檢查是否重複做太多工作。若每個元素又掃描完整陣列,輸入擴大時可能變成平方級工作;但不要為了效能把原本正確的順序規則改掉。

LeetCode 的失敗案例說明也提醒:跨測試使用的全域、靜態或類別狀態可能造成單獨執行正常、連續評測失敗。若你用了保存結果的成員變數,就檢查每次呼叫是否正確初始化;不要直接把責任推給平台。

對第一題而言,最有用的修正紀錄很短:「我把 > 寫成 >=;原樣例看不出差別;新增相等案例後找到錯誤。」它比「這題粗心」更能幫你避免重犯,因為指出了具體假設。

卡住可以看解答,但要分兩次完成學習

先區分卡住的位置。你知道要掃描,卻忘了語法,可以查語言文件;你知道規格,卻想不出方法,可以先看提示;你連輸出意思都不確定,就應先重讀範例。直接把完整解答貼進編輯器,可能讓這三種問題混在一起。

閱讀解答時,先找核心想法,再看程式。「為什麼可以提早回傳?」「為什麼這裡需要集合?」「資料改變後,哪些資訊仍然成立?」如果只能逐行念語法,還沒真正理解。

看懂之後把解答關掉,重新建立空白檔案。先寫規格與自己的案例,再重寫程式。你可以使用不同變數名稱,但重點不是避免字面相同,而是每一個決策都能解釋。回想不起來時,記下缺口,再回頭補,不要把靠記憶抄出的版本當作獨立完成。

最後加一個規格變化:如果題目要「最後一個大於 limit 的位置」,原本找到就 return 的程式為什麼不再適用?能回答這個問題,才表示你知道原解法依賴什麼條件。這是本文的自我檢查,不是平台官方評分項目。

下一題怎麼練?讓相同方法接受不同考驗

在換題以前,先確認你不是只記得剛才的畫面。把原創練習的數值換掉,用 [8, 1, 9] 與 limit 7 手算一次,再把 limit 改成 9。前者答案是 0,後者答案是 −1;程式的判斷不應依賴之前那組數字。

還可以把陣列的順序換成 [1, 9, 8]。答案改成 1,說明位置由原始順序決定。若你為了方便而排序,即使保留了相同元素,也可能改變答案。這是「做出可用輸出」與「做出符合規格輸出」的差別。

當你可以自己設計這種變化,再進入另一個概念比較合理。暫時仍需要查語法並不代表練習失敗,但應能指出自己查的是哪個語法,而不是把完整解法交給別人決定。

它們是不同來源的練習,不是 LeetCode 題單,也不保證符合你的目前程度;先讀限制,再選一題。

練習這次練什麼
Increment a Digit-Array Integer by One進位、最後一位與連續 9 的邊界
Find a String Containing Another字串條件與回傳規則
Compress a String by Run-Length Counts, Keeping the Original When Not Shorter相等長度與分支判斷
Merge Sorted Arrays先做雙陣列部分,檢查指標與剩餘元素
Identify and prevent code-breaking inputs說明哪個輸入會打破你的假設

完成每題後,只留一段可以回看的紀錄:題目契約、第一次錯在哪裡、能抓到錯誤的案例、獨立重寫的結果。不要只記題號,也不用把整份解答複製到筆記。

一份有用的檢討紀錄,應該讓你知道下一次先查什麼

下面仍以本文的自製練習為例。它不是成功故事,而是三種常見錯誤的檢討方式;你可以使用相同欄位,但每次要填真正發生的錯誤。

看到的現象最小反例與原因下一次的具體檢查
範例通過,相等時失敗[5]、limit 5;把 > 寫成 >=讀題時圈出「嚴格」,測試包含相等值
顯示了正確數字,呼叫結果卻不對印出了索引,但沒有回傳它看模板要輸出文字,還是回傳值
第一個符合值後還繼續更新答案[7, 2, 8]、limit 5;最後留下索引 2確認「第一個」是否意味找到即可停止

第二種情況可以在本地驗證:呼叫函式並把「回傳值」保存到變數,再檢查變數。不要只看終端機上有沒有印出文字。如果函式沒有明確回傳,在 Python 中可能得到 None,這與回傳整數 1 是不同結果。

第三種情況不是語法問題。程式可能能正常執行,也沒有錯誤訊息,但實作的是另一個規則。這提醒你:除錯不能只查編輯器畫紅線的地方,還要核對題目中「第一個」、「所有」、「至少」與「恰好」這些條件。

改完後先重跑失敗案例,再跑原本正常的案例。若只驗證新案例,你可能修好了相等值,卻意外把第一個符合值的處理弄壞。把兩者一起保留,下一次修改時就有明確的檢查依據。

新手常問的三個問題:現在就需要題單、最佳解與排名嗎?

第一題不必從長題單開始。題單有助於組織不同概念,但不會替你讀懂某題的回傳規則。如果你還無法獨立完成一個小函式,先把這個循環走順,再用題單安排下一個概念,通常比較容易看出進步。

也不需要一看到解答更短,就認定自己的版本不好。上面的單次掃描已經有清楚的理由:為了判斷不存在的情況,最壞需要看完每個值。比較解法時,要問它是否符合限制、是否好驗證,而不只是行數較少。

至於執行時間或記憶體顯示,先用來發現自己的程式是否有明顯問題,不要把一次數字變化當成能力排名。若要比較兩個實作,應使用一致的輸入、環境與測量方式;本文沒有進行平台效能基準測試。

如果你問「多久能開始面試」,完成第一題仍不能給出可靠時間表。更實際的檢查是:換一組資料還能推理嗎?面對失敗能找到原因嗎?有人問為什麼這樣寫,你能回答嗎?這些問題會指出下一步需要補的是語法、方法,還是說明能力。

當你能穩定完成這個循環,再考慮按概念安排長期練習,或針對面試加入口頭說明與需求變動。如果想比較兩種平台的用途,可讀 LeetCode 與 HackerRank 的準備方式比較。第一題的成功標準很具體:你知道自己交了什麼,能找到反例,也能不看解答再寫一次。

資料來源與延伸閱讀