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

ข้อ 40 · LC1161 Maximum Level Sum of a Binary Tree (ชั้นผลรวมมากสุด) 🟡

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

หาเลขชั้นที่ผลรวมค่ามากที่สุด ด้วย BFS วนทีละชั้นแล้วบวกและเทียบ

โจทย์ (LC1161): กำหนด root ของ binary tree มาให้ โดยกำหนดว่า level ของ root คือ 1, level ของ child คือ 2 ไล่ลงไปเรื่อย ๆ ให้ return เลข level x ที่น้อยที่สุด ซึ่งผลรวมค่าของ node ทั้งหมดใน level x นั้นมากที่สุด (ค่าติดลบมีได้)

Example 1
Input:
root = [1,7,0,7,-8,null,null]
Output:
2
Explanation:
ชั้น 1 = 1, ชั้น 2 = 7 + 0 = 7, ชั้น 3 = 7 + (-8) = -1 — ชั้นที่ผลรวมมากที่สุดคือชั้น 2
Example 2
Input:
root = [989,null,10250,98693,-89388,null,null,null,-32127]
Output:
2
Constraints (ข้อจำกัด)
  • จำนวน node อยู่ระหว่าง 1 ถึง 10^4
  • -10^5 <= Node.val <= 10^5

แนวทาง — ต้องใช้อะไร & คิดยังไง

ใช้ BFS loop ทีละ level ตาม template เพิ่ม counter level ที่บวก 1 ทุกครั้งที่ขึ้น level ใหม่ และ track ผลรวมค่าทุก node ใน level เป็น total เมื่อจบ level ก็ compare กับผลรวมมากสุดที่เคยเจอ

โจทย์นี้ทำด้วย DFS (พก level ลงไปแล้วสะสมผลรวมต่อ level) ก็ได้ แต่ BFS เข้ากับโจทย์ "เป็น level" อย่างเป็นธรรมชาติกว่า เพราะเรากำหนดขอบเขตแต่ละ level ชัดเจนด้วย size

  1. ตั้ง best_sum = -inf, best_level = 1, level = 0, queue = deque([root])
  2. loop while queue: เพิ่ม level += 1 (ขึ้น level ใหม่)
  3. จด size = len(queue) และ total = 0
  4. loop pop ทั้ง level: total += node.val แล้ว append left child, right child เข้า queue
  5. จบ level: ถ้า total > best_sum update best_sum และ best_level = level
  6. return best_level
จุดพลาดที่พบบ่อย

initialize (ตั้งค่าเริ่มต้น) best_sum ด้วย 0 จะพังถ้าทุก level ผลรวมติดลบ ต้องเริ่ม float('-inf') และใช้ > (ไม่ใช่ >=) เพื่อให้ผลรวมเสมอกันเก็บ level แรกไว้ตามโจทย์ อีกทั้ง level เริ่มนับที่ 1 ไม่ใช่ 0

ไล่ทีละสเต็ป

จำลองบนต้น [1,7,0,7,-8,null,null]

levelnode ใน leveltotalbest_sum / best_level หลัง level นี้
1[1]11 / 1
2[7, 0]77 / 2
3[7, -8]-17 / 2 (ไม่อัปเดต)
▶ เฉลยละเอียด (ลองเองก่อนนะ)
เฉลย (Python) — โค้ดนี้รันได้จริงpython
# LeetCode ให้ class นี้มาให้แล้ว ที่เขียนไว้ตรงนี้เพื่อให้บล็อกนี้รันได้เองทั้งก้อน
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


from collections import deque

def maxLevelSum(root):
    best_sum = float('-inf')   # ผลรวมมากสุดที่เจอ (เริ่ม -inf กันค่าติดลบ)
    best_level = 1             # เลขชั้นที่ให้ผลรวมมากสุด
    level = 0
    queue = deque([root])
    while queue:
        level += 1            # ขึ้นชั้นใหม่
        size = len(queue)
        total = 0
        for _ in range(size):
            node = queue.popleft()
            total += node.val         # บวกทุก node ในชั้นนี้
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        if total > best_sum:          # เจอชั้นที่รวมมากกว่าเดิม
            best_sum = total
            best_level = level
    return best_level

# ต้นไม้ [1, 7, 0, 7, -8, null, null]
root = TreeNode(1, TreeNode(7, TreeNode(7), TreeNode(-8)), TreeNode(0))
print(maxLevelSum(root))
Output
2

โครงเดียวกับข้อก่อน เพิ่มตัวนับ level ที่บวก 1 ทุกครั้งที่เริ่มชั้นใหม่ และตัวแปร total บวกค่าทุก node ในชั้น เมื่อจบชั้นก็เทียบ total กับ best_sum ถ้ามากกว่าจึงอัปเดต ใช้ > (มากกว่าเท่านั้น ไม่ใช่ >=) เพื่อให้เมื่อผลรวมเสมอกัน เราเก็บชั้นแรก (เลขน้อยกว่า) ไว้ตามที่โจทย์ต้องการ

จุดพลาดที่พบบ่อยคือเริ่ม best_sum ด้วย 0 ซึ่งพังทันทีถ้าทุกชั้นมีผลรวมติดลบ ต้องเริ่มด้วย float('-inf') และอย่าลืมว่าโจทย์นับชั้นเริ่มที่ 1 ไม่ใช่ 0 โจทย์นี้ทำด้วย DFS ก็ได้ แต่ BFS เข้ากับโจทย์ "เป็นชั้น" อย่างเป็นธรรมชาติกว่า

Time O(n) แตะทุก node ครั้งเดียว · Space O(w) โดย w คือความกว้างมากสุดของต้นไม้ (จำนวน node มากสุดในคิวพร้อมกัน)

💡 สรุป pattern

BFS + ตัวสะสมต่อชั้น (ผลรวม/จำนวน/max) แล้วเทียบข้ามชั้น: เมื่อโจทย์ถามหา "ชั้นที่ดีที่สุด" ใช้ level counter + ตัวแปรเก็บแชมป์ ด้วยเงื่อนไข > เพื่อรักษาชั้นแรกเมื่อเสมอ