Notes & software courses · Free to learn
Aph's Blog
On this page

เจอโจทย์ใหม่ จะรู้ได้ยังไงว่าใช้หมวดไหน

👋 อ่านฟรีทั้งหมดบน Aph's Blog — เนื้อหาภาษาไทย ทำตามทีละหน้าใน sidebar ได้เลย หากมีข้อเสนอแนะหรืออยากให้เพิ่มหัวข้อไหน บอกได้เสมอ

คอร์สนี้มี 22 หมวด แต่ละหมวดสอนแยกกัน หน้านี้คือส่วนที่หายไป — วิธีตัดสินใจว่าโจทย์ที่ไม่เคยเห็นควรหยิบหมวดไหนมาใช้

ปัญหาที่เจอกันทุกคนหลังเรียนจบหลายหมวด: เข้าหน้าหมวด Sliding Window ก็แก้โจทย์ sliding window ได้ เข้าหน้า Two Pointers ก็แก้ได้ แต่พอเจอโจทย์เปล่า ๆ ที่ไม่มีป้ายบอกว่าอยู่หมวดไหน ก็นึกไม่ออกว่าจะเริ่มจากอะไร นั่นไม่ใช่เพราะยังไม่เก่งพอ แต่เพราะทักษะ "เลือกเครื่องมือ" เป็นทักษะแยกอีกอันหนึ่ง ที่ไม่ได้มาฟรีจากการฝึกแต่ละหมวด

หน้านี้จะให้เครื่องมือสามชั้น ใช้ตามลำดับ: อ่าน constraint เพื่อเดาความเร็วที่ต้องได้ ก่อน แล้วดูรูปร่างข้อมูล แล้วดูคำที่โจทย์ใช้ ชั้นแรกเป็นชั้นที่คนมองข้ามที่สุดแต่ตัดตัวเลือกได้เยอะที่สุด

ชั้นที่ 1 · อ่าน constraint แล้วเดา Big-O ที่ต้องได้

โจทย์ทุกข้อบอกขนาดข้อมูลสูงสุดไว้ในส่วน constraint และตัวเลขนั้นบอกใบ้ว่าคำตอบต้องเร็วระดับไหน ซึ่งแปลกลับไปเป็นหมวดที่เป็นไปได้ ระบบตรวจส่วนใหญ่ให้เวลาประมาณ 1 วินาที ซึ่งรันคำสั่งได้ราว ๆ 100 ล้านครั้ง ลองดูว่าแต่ละขนาดข้อมูลทำให้อะไรเป็นไปไม่ได้

จำนวนครั้งที่ต้องทำงาน เมื่อ n โตขึ้นpython
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}")
Output
         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 ≤ 10O(n!) ก็ยังผ่านBacktracking (เรียงสับเปลี่ยนทุกแบบ)
n ≤ 20 – 25O(2ⁿ) ผ่านBacktracking, Bit Manipulation (bitmask ทุก subset)
n ≤ 500O(n³) ผ่านDP หลายมิติ
n ≤ 2,000 – 5,000O(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 ที่มี .nextLinked List (มักคู่กับ two pointers แบบ slow/fast)
node ที่มี .left / .rightTree 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)
สองตำแหน่งบนข้อมูลที่เรียงแล้ว, หัวกับท้ายเดินเข้าหากัน, palindromeTwo Pointers
ช่วง ต่อเนื่อง (subarray / substring) + ยาวสุด / ผลรวมมากสุด / มีไม่เกิน k ตัวSliding Window
ผลรวมของช่วง i ถึง j และถูกถามซ้ำหลายครั้ง / running totalPrefix Sum
นับความถี่, เคยเจอค่านี้แล้วหรือยัง, จับคู่ค่ากับตำแหน่งเดิมHash Map
ต้องย้อนดูตัวที่เพิ่งเจอล่าสุดก่อน, วงเล็บสมดุล, undoStack
ตัวถัดไปที่มากกว่า / น้อยกว่า (next greater / previous smaller)Monotonic Stack
เข้าก่อนออกก่อน, จำลองคิว, ประมวลผลทีละชั้นQueue
ความลึกของ tree, path จากรากถึงใบ, ต้องรู้คำตอบของลูกก่อนจึงตอบพ่อได้Tree DFS
ทำทีละ ชั้น (level) เช่นค่าขวาสุดของแต่ละชั้น, ความกว้างของ treeTree 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

ถ้ามันไม่เข้าหมวดไหนเลย

จะมีโจทย์ที่ดูแล้วไม่ตรงกับแถวไหนในตารางข้างบนเลย ตอนนั้นห้ามนั่งนึกชื่อหมวดต่อ เพราะมันไม่มาเอง ให้เปลี่ยนไปทำสามขั้นนี้แทน ซึ่งเป็นวิธี สร้าง คำตอบ ไม่ใช่การ จำ คำตอบ

  1. เขียนวิธีที่ช้าที่สุดแต่ถูกแน่ ๆ ให้ได้ก่อน (brute force) โดยไม่สนความเร็วเลย ถ้าเขียนขั้นนี้ไม่ได้ แปลว่ายังไม่เข้าใจโจทย์ ไม่ใช่ยังไม่รู้เทคนิค
  2. หาว่ามันทำงานอะไรซ้ำ ๆ โดยไม่จำเป็น — ทุกเทคนิคเร็ว ๆ ในคอร์สนี้เกิดจากการกำจัดงานซ้ำแบบใดแบบหนึ่งทั้งนั้น
  3. จับคู่ชนิดของงานซ้ำกับเทคนิค ตามตารางด้านล่าง
งานซ้ำที่พบใน brute forceเทคนิคที่กำจัดมัน
คำนวณผลรวมของช่วงเดิมใหม่ทุกครั้งPrefix Sum (คำนวณไว้ล่วงหน้า) หรือ Sliding Window (ต่อยอดจากค่าเดิม)
ไล่ถามว่า "ค่านี้เคยเจอไหม" ด้วยการวนดูทั้งลิสต์Hash Map / Set (ถามครั้งเดียวจบ)
เทียบทุกคู่ ทั้งที่ข้อมูลเรียงอยู่แล้วTwo Pointers หรือ Binary Search
คำนวณคำตอบของปัญหาย่อยเดิมซ้ำหลายครั้งDP หรือ memo (จำคำตอบที่เคยคิดแล้ว)
หาตัวมากสุดใหม่ทุกครั้งหลังข้อมูลเปลี่ยนHeap
ไล่หา "ตัวถัดไปที่มากกว่า" ของทุกตำแหน่งด้วยการวนไปข้างหน้าทุกครั้งMonotonic Stack
ลองทุกคำตอบที่เป็นไปได้ทีละค่า ทั้งที่คำตอบมีทิศทางชัด (มากขึ้นก็ยิ่งง่าย/ยาก)Binary Search on answer
ประโยคเดียวที่ควรจำจากหน้านี้

อย่าเริ่มจากถามว่า "โจทย์นี้ใช้เทคนิคอะไร" เพราะเป็นคำถามที่ตอบได้เฉพาะเมื่อเคยเห็นโจทย์คล้ายกันมาก่อน ให้เริ่มจาก "วิธีที่ช้าแต่ถูกคืออะไร" แล้วถามต่อว่า "มันเสียเวลาไปกับงานซ้ำแบบไหน" — เทคนิคจะโผล่มาเองจากคำถามที่สอง และนั่นคือทักษะที่ใช้ได้กับโจทย์ที่ไม่เคยเห็น