On this page
เจอโจทย์ใหม่ จะรู้ได้ยังไงว่าใช้หมวดไหน
คอร์สนี้มี 22 หมวด แต่ละหมวดสอนแยกกัน หน้านี้คือส่วนที่หายไป — วิธีตัดสินใจว่าโจทย์ที่ไม่เคยเห็นควรหยิบหมวดไหนมาใช้
ปัญหาที่เจอกันทุกคนหลังเรียนจบหลายหมวด: เข้าหน้าหมวด Sliding Window ก็แก้โจทย์ sliding window ได้ เข้าหน้า Two Pointers ก็แก้ได้ แต่พอเจอโจทย์เปล่า ๆ ที่ไม่มีป้ายบอกว่าอยู่หมวดไหน ก็นึกไม่ออกว่าจะเริ่มจากอะไร นั่นไม่ใช่เพราะยังไม่เก่งพอ แต่เพราะทักษะ "เลือกเครื่องมือ" เป็นทักษะแยกอีกอันหนึ่ง ที่ไม่ได้มาฟรีจากการฝึกแต่ละหมวด
หน้านี้จะให้เครื่องมือสามชั้น ใช้ตามลำดับ: อ่าน constraint เพื่อเดาความเร็วที่ต้องได้ ก่อน แล้วดูรูปร่างข้อมูล แล้วดูคำที่โจทย์ใช้ ชั้นแรกเป็นชั้นที่คนมองข้ามที่สุดแต่ตัดตัวเลือกได้เยอะที่สุด
ชั้นที่ 1 · อ่าน constraint แล้วเดา Big-O ที่ต้องได้
โจทย์ทุกข้อบอกขนาดข้อมูลสูงสุดไว้ในส่วน constraint และตัวเลขนั้นบอกใบ้ว่าคำตอบต้องเร็วระดับไหน ซึ่งแปลกลับไปเป็นหมวดที่เป็นไปได้ ระบบตรวจส่วนใหญ่ให้เวลาประมาณ 1 วินาที ซึ่งรันคำสั่งได้ราว ๆ 100 ล้านครั้ง ลองดูว่าแต่ละขนาดข้อมูลทำให้อะไรเป็นไปไม่ได้
import math
LIMIT = 100_000_000 # จำนวนคำสั่งคร่าว ๆ ที่รันจบใน ~1 วินาที
print(f"{'n':>10} | {'O(n)':>14} | {'O(n log n)':>14} | {'O(n^2)':>18} | ผ่านได้ถึง")
for n in [20, 500, 5_000, 100_000, 1_000_000]:
a = n
b = n * max(1, int(math.log2(n)))
c = n * n
ok = "O(n^2)" if c <= LIMIT else ("O(n log n)" if b <= LIMIT else "O(n)")
print(f"{n:>10,} | {a:>14,} | {b:>14,} | {c:>18,} | {ok}") n | O(n) | O(n log n) | O(n^2) | ผ่านได้ถึง
20 | 20 | 80 | 400 | O(n^2)
500 | 500 | 4,000 | 250,000 | O(n^2)
5,000 | 5,000 | 60,000 | 25,000,000 | O(n^2)
100,000 | 100,000 | 1,600,000 | 10,000,000,000 | O(n log n)
1,000,000 | 1,000,000 | 19,000,000 | 1,000,000,000,000 | O(n log n)สังเกตว่าที่ n = 100,000 คอลัมน์ O(n²) พุ่งไปหนึ่งหมื่นล้าน คือเกินงบไป 100 เท่า นั่นแปลว่าถ้าโจทย์บอก n ถึงแสน แล้วเรากำลังคิดวิธีที่มี loop ซ้อนสองชั้น ให้รู้ตัวได้เลยว่าคิดผิดทางแล้ว ไม่ต้องเสียเวลาเขียนให้เสร็จก่อนแล้วค่อยรู้ ในทางกลับกันถ้า n เล็กมากอย่าง 20 แปลว่าโจทย์ กำลังอนุญาต ให้เราทำวิธีที่ช้าเวอร์อย่างการลองทุกความเป็นไปได้ ซึ่งเป็นใบ้ที่ตรงตัวมาก
| n สูงสุดใน constraint | ต้องได้ความเร็วราว ๆ | หมวดที่มักเป็นคำตอบ |
|---|---|---|
| n ≤ 10 | O(n!) ก็ยังผ่าน | Backtracking (เรียงสับเปลี่ยนทุกแบบ) |
| n ≤ 20 – 25 | O(2ⁿ) ผ่าน | Backtracking, Bit Manipulation (bitmask ทุก subset) |
| n ≤ 500 | O(n³) ผ่าน | DP หลายมิติ |
| n ≤ 2,000 – 5,000 | O(n²) ผ่าน | DP หลายมิติ, DP 1 มิติ, loop ซ้อนสองชั้นแบบตรงไปตรงมา |
| n ≤ 10⁵ – 10⁶ | ต้อง O(n) หรือ O(n log n) | Two Pointers, Sliding Window, Prefix Sum, Hash Map, Heap, Binary Search, Monotonic Stack |
| n ≥ 10⁷ หรือค่าตัวเลขใหญ่มาก (10⁹) | ต้อง O(n) หรือ O(log n) | Bit Manipulation, Binary Search on answer (ค้นบน "คำตอบ" ไม่ใช่บนข้อมูล) |
เห็น n ≤ 20 ให้คิดถึง "ลองทุกแบบ" ก่อนเลย เพราะไม่มีเหตุผลอื่นที่โจทย์จะจำกัด n ให้เล็กขนาดนั้น และเห็นเลข 10⁹ หรือ 10¹⁸ ในช่อง ค่า (ไม่ใช่ช่องจำนวนข้อมูล) ให้คิดถึง binary search บนคำตอบ หรือเลขคณิต/บิต เพราะเป็นไปไม่ได้ที่จะไล่ทุกค่า
ชั้นที่ 2 · รูปร่างข้อมูลตัดหมวดให้เหลือไม่กี่อัน
ก่อนดูว่าโจทย์ถามอะไร ให้ดูว่าโจทย์ ให้อะไรมา รูปร่างของข้อมูลตัดหมวดออกไปได้ทันทีเป็นกลุ่ม ๆ
| โจทย์ให้อะไรมา | เหลือหมวดที่เป็นไปได้แค่นี้ |
|---|---|
| array หรือ string ธรรมดา | Array/String, Two Pointers, Sliding Window, Prefix Sum, Hash Map, Binary Search, Monotonic Stack, DP |
| array ที่เรียงมาแล้ว (โจทย์บอกว่า sorted) | Two Pointers, Binary Search — คำว่า sorted แทบไม่เคยเป็นข้อมูลฟรี มันคือใบ้ |
| node ที่มี .next | Linked List (มักคู่กับ two pointers แบบ slow/fast) |
| node ที่มี .left / .right | Tree DFS, Tree BFS, BST |
| จุดกับเส้นเชื่อม / ตาราง 2 มิติที่เดินได้ | Graph DFS, Graph BFS |
| ลิสต์ของช่วง [start, end] | Intervals (เกือบทุกครั้งเริ่มด้วยการ sort ตาม start) |
| ลิสต์ของคำจำนวนมาก + ถามเรื่องคำขึ้นต้น | Trie |
| ตัวเลขล้วน ๆ ไม่มีโครงสร้าง | Bit Manipulation, คณิตศาสตร์, DP |
ชั้นที่ 3 · คำที่โจทย์ใช้ → หมวด
ชั้นนี้คือตารางที่ใช้บ่อยที่สุดเวลาฝึก ให้มองหาคำหรือรูปคำถามในโจทย์ แล้วเทียบกับแถวเหล่านี้
| สัญญาณในโจทย์ | หมวด |
|---|---|
| แก้ใน array เดิม / in-place / return ความยาวใหม่ | Two Pointers (read-write) |
| สองตำแหน่งบนข้อมูลที่เรียงแล้ว, หัวกับท้ายเดินเข้าหากัน, palindrome | Two Pointers |
| ช่วง ต่อเนื่อง (subarray / substring) + ยาวสุด / ผลรวมมากสุด / มีไม่เกิน k ตัว | Sliding Window |
| ผลรวมของช่วง i ถึง j และถูกถามซ้ำหลายครั้ง / running total | Prefix Sum |
| นับความถี่, เคยเจอค่านี้แล้วหรือยัง, จับคู่ค่ากับตำแหน่งเดิม | Hash Map |
| ต้องย้อนดูตัวที่เพิ่งเจอล่าสุดก่อน, วงเล็บสมดุล, undo | Stack |
| ตัวถัดไปที่มากกว่า / น้อยกว่า (next greater / previous smaller) | Monotonic Stack |
| เข้าก่อนออกก่อน, จำลองคิว, ประมวลผลทีละชั้น | Queue |
| ความลึกของ tree, path จากรากถึงใบ, ต้องรู้คำตอบของลูกก่อนจึงตอบพ่อได้ | Tree DFS |
| ทำทีละ ชั้น (level) เช่นค่าขวาสุดของแต่ละชั้น, ความกว้างของ tree | Tree BFS |
| tree ที่ค่าเรียงกันอยู่ / ค้นหาใน tree ให้เร็ว / บรรพบุรุษร่วม | BST |
| นับกลุ่มที่เชื่อมกัน, มีทางเดินไปถึงกันไหม, นับเกาะ | Graph DFS |
| ระยะทาง สั้นที่สุด บนกราฟที่ทุกก้าวมีค่าเท่ากัน / จำนวนก้าวน้อยสุด | Graph BFS |
| k ตัวที่มากสุด/น้อยสุด, ตัวที่ดีที่สุดตอนนี้ ที่เปลี่ยนไปเรื่อย ๆ, ข้อมูลไหลเข้ามาไม่หยุด | Heap |
| เรียงแล้วและหาค่า / หาค่าน้อยสุดที่ยังทำได้ / คำว่า "อย่างน้อย" กับ "อย่างมาก" ในคำตอบ | Binary Search |
| ขอ รายการ คำตอบทั้งหมด (ทุก subset, ทุก permutation, ทุกเส้นทาง) และ n เล็ก | Backtracking |
| นับจำนวนวิธี / ค่าที่ดีที่สุด ที่ขึ้นกับผลของขั้นก่อนหน้า และไม่ต้องบอกว่าคำตอบคืออะไรบ้าง | DP 1 มิติ |
| สองอย่างมาเทียบกัน (สอง string, ตาราง 2 มิติ, ของกับงบ) | DP หลายมิติ |
| XOR, บิต, หาตัวที่ไม่ซ้ำในบรรดาตัวที่ซ้ำเป็นคู่, เลขยกกำลังสอง | Bit Manipulation |
| คำที่ขึ้นต้นด้วย (prefix), autocomplete, ค้นคำจำนวนมากซ้ำ ๆ | Trie |
| ช่วงเวลาซ้อนทับ, รวมช่วง, ห้องประชุม | Intervals |
คู่ที่คนสับสนกันบ่อยที่สุด
ถ้าตัดเหลือสองหมวดแล้วยังเลือกไม่ได้ ให้ดูตารางนี้ — แต่ละแถวคือคำถามหนึ่งคำถามที่แยกสองหมวดออกจากกันได้เด็ดขาด
| สับสนระหว่าง | ถามตัวเองว่า | คำตอบ |
|---|---|---|
| Two Pointers vs Sliding Window | เราสนใจแค่ค่าที่ตัวชี้สองตัวชี้อยู่ หรือสนใจ ทุกอย่างที่อยู่ระหว่างมัน | สนใจแค่สองจุด = Two Pointers / สนใจทั้งช่วง (คำว่า "ต่อเนื่อง") = Sliding Window |
| Hash Map vs Two Pointers | โจทย์ขอ index เดิม หรือห้ามเปลี่ยนลำดับหรือเปล่า | ถ้าใช่ sort ไม่ได้ → Hash Map / ถ้าไม่ใช่และเรียงได้ → Two Pointers |
| Graph DFS vs BFS | โจทย์ถามคำว่า สั้นที่สุด หรือ น้อยที่สุด ไหม | ถาม = BFS (การันตีสั้นสุด) / ไม่ถาม แค่ให้ไปให้ถึงหรือให้นับกลุ่ม = DFS เขียนสั้นกว่า |
| Heap vs การ sort | ต้องการทั้งหมดเรียงครบ หรือแค่ k ตัวหัวแถว | ทั้งหมด = sort / แค่ k ตัว หรือข้อมูลยังไหลเข้ามาเรื่อย ๆ = Heap |
| DP vs Backtracking | โจทย์ขอ ตัวเลข (กี่วิธี / ดีสุดเท่าไหร่) หรือขอ ของ (คำตอบทุกชุด) | ขอตัวเลข = DP / ขอรายการคำตอบ = Backtracking |
| Stack vs Monotonic Stack | เราต้องการแค่ตัวล่าสุด หรือต้องการ "ตัวถัดไปที่มากกว่า/น้อยกว่า" | ตัวล่าสุด = Stack ธรรมดา / ตัวถัดไปที่มากกว่า = Monotonic Stack |
| Tree DFS vs Tree BFS | คำตอบขึ้นกับ ความลึก/เส้นทาง หรือขึ้นกับ ชั้น | ความลึกหรือเส้นทาง = DFS / ทีละชั้น = BFS |
ถ้ามันไม่เข้าหมวดไหนเลย
จะมีโจทย์ที่ดูแล้วไม่ตรงกับแถวไหนในตารางข้างบนเลย ตอนนั้นห้ามนั่งนึกชื่อหมวดต่อ เพราะมันไม่มาเอง ให้เปลี่ยนไปทำสามขั้นนี้แทน ซึ่งเป็นวิธี สร้าง คำตอบ ไม่ใช่การ จำ คำตอบ
- เขียนวิธีที่ช้าที่สุดแต่ถูกแน่ ๆ ให้ได้ก่อน (brute force) โดยไม่สนความเร็วเลย ถ้าเขียนขั้นนี้ไม่ได้ แปลว่ายังไม่เข้าใจโจทย์ ไม่ใช่ยังไม่รู้เทคนิค
- หาว่ามันทำงานอะไรซ้ำ ๆ โดยไม่จำเป็น — ทุกเทคนิคเร็ว ๆ ในคอร์สนี้เกิดจากการกำจัดงานซ้ำแบบใดแบบหนึ่งทั้งนั้น
- จับคู่ชนิดของงานซ้ำกับเทคนิค ตามตารางด้านล่าง
| งานซ้ำที่พบใน brute force | เทคนิคที่กำจัดมัน |
|---|---|
| คำนวณผลรวมของช่วงเดิมใหม่ทุกครั้ง | Prefix Sum (คำนวณไว้ล่วงหน้า) หรือ Sliding Window (ต่อยอดจากค่าเดิม) |
| ไล่ถามว่า "ค่านี้เคยเจอไหม" ด้วยการวนดูทั้งลิสต์ | Hash Map / Set (ถามครั้งเดียวจบ) |
| เทียบทุกคู่ ทั้งที่ข้อมูลเรียงอยู่แล้ว | Two Pointers หรือ Binary Search |
| คำนวณคำตอบของปัญหาย่อยเดิมซ้ำหลายครั้ง | DP หรือ memo (จำคำตอบที่เคยคิดแล้ว) |
| หาตัวมากสุดใหม่ทุกครั้งหลังข้อมูลเปลี่ยน | Heap |
| ไล่หา "ตัวถัดไปที่มากกว่า" ของทุกตำแหน่งด้วยการวนไปข้างหน้าทุกครั้ง | Monotonic Stack |
| ลองทุกคำตอบที่เป็นไปได้ทีละค่า ทั้งที่คำตอบมีทิศทางชัด (มากขึ้นก็ยิ่งง่าย/ยาก) | Binary Search on answer |
อย่าเริ่มจากถามว่า "โจทย์นี้ใช้เทคนิคอะไร" เพราะเป็นคำถามที่ตอบได้เฉพาะเมื่อเคยเห็นโจทย์คล้ายกันมาก่อน ให้เริ่มจาก "วิธีที่ช้าแต่ถูกคืออะไร" แล้วถามต่อว่า "มันเสียเวลาไปกับงานซ้ำแบบไหน" — เทคนิคจะโผล่มาเองจากคำถามที่สอง และนั่นคือทักษะที่ใช้ได้กับโจทย์ที่ไม่เคยเห็น