กระเบื้องตัวเลขสองแผ่นบนโต๊ะมิ้นต์ ชีไปยังแผ่นเป้าหมายขอบสีอำพัน

LeetCode Two Sum: ห้าแนวคิดจากช้าสุดถึงแผนที่หนึ่งรอบ

น้องกายEngineering

โจทย์ถามว่า ในอาเรย์ตัวเลข มีสองช่องไหนที่บวกกันได้เท่า target ให้คืนตำแหน่งทั้งสอง ข้อนี้เป็นข้อแรกที่หลายคนเจอในสัมภาษณ์

สมมติอินพุต [2, 7, 11, 15] และ target = 9 คำตอบคือตำแหน่งของ 2 กับ 7

แนวทางที่ 1: ลองทุกคู่ (Brute force)

วน i แล้ววน j > i ถ้า nums[i] + nums[j] == target ก็ตอบ

  • เวลาประมาณ O(n²) พื้นที่ O(1)
  • ชัดมาก เหมาะมือใหม่พิสูจน์ความเข้าใจโจทย์
  • ไวท์บอร์ดใช้เปิดบทสนทนาได้ แต่ควรบอกเองว่าช้าเมื่อ n ใหญ่

แนวทางที่ 2: เรียงแล้วใช้สองตัวชี้

ถ้าโจทย์ยอมให้สนใจค่ามากกว่าตำแหน่งเดิม หรือเราสร้างคู่ (ค่า, ตำแหน่ง) แล้วเรียง ตามด้วยสองตัวชี้จากหัวท้าย

  • เวลา O(n log n) จากเรียง พื้นที่ O(n) ถ้านับอาร์เรย์คู่
  • ใน Two Sum มาตรฐานที่ต้องคืน index เดิม วิธีนี้พลาดง่ายถ้าลืมเก็บ index

แนวทางที่ 3: Hash map สองรอบ

รอบแรกเก็บค่าเป็นคีย์และตำแหน่งเป็นค่า รอบสองหา target - nums[i] ในแมป โดยไม่ใช้ตำแหน่งตัวเอง

  • เวลา O(n) พื้นที่ O(n)
  • อธิบายง่าย แต่เดินสองรอบ

แนวทางที่ 4: Hash map หนึ่งรอบ (แนะนำหลัก)

เดินทีละตัว คำนวณ need = target - nums[i] ถ้า need อยู่ในแมปแล้ว ให้ตอบ ถ้ายังไม่มี ใส่ค่าปัจจุบันลงแมป

นี่เป็นตัวอย่างโค้ดแบบ fragment / pseudocode สำหรับอธิบายแนวคิด:

def two_sum(nums, target):
    seen = {}
    for i, value in enumerate(nums):
        need = target - value
        if need in seen:
            return [seen[need], i]
        seen[value] = i
  • เวลา O(n) พื้นที่ O(n)
  • ชัดและเป็นคำตอบที่สัมภาษณ์ส่วนใหญ่คาดหวัง

แนวทางที่ 5: เมื่อข้อมูลพิเศษ

ถ้าอาร์เรย์เรียงอยู่แล้วและโจทย์ยอมคืนค่าแทน index หรือมีขอบเขตค่าแคบ อาจใช้สองตัวชี้หรือตารางนับ แต่ใน Two Sum คลาสสิกบน LeetCode แผนที่หนึ่งรอบยังเป็นตัวหลัก

แผนภาพด้านล่างเป็น fragment / pseudocode ของลำดับคิด:

flowchart LR
  A[อ่านค่าปัจจุบัน] --> B{need อยู่ในแมป?}
  B -->|ใช่| C[คืนสองตำแหน่ง]
  B -->|ไม่| D[เก็บค่าปัจจุบันลงแมป]
  D --> A

เลือกใช้เมื่อไหร่

สถานการณ์แนะนำ
มือใหม่เพิ่งอ่านโจทย์Brute force แล้วค่อยย่น
ไวท์บอร์ดสัมภาษณ์Hash map หนึ่งรอบ พร้อมพูด tradeoff พื้นที่
โปรดักชัน hot pathHash map หนึ่งรอบ หรือโครงสร้างที่เหมาะข้อมูลจริงหลังวัดแล้ว

Recap

  • พูดโจทย์และตัวอย่างก่อนลงโค้ด
  • เริ่มจาก O(n²) ได้ แต่จบที่ O(n) ด้วยแมป
  • ระวังคืน index เดิม ไม่ใช่ค่า
  • ทบทวนเคสตัวเลขซ้ำและไม่มีคำตอบตามสัญญาโจทย์ครับ