450. Delete Node in a BST

練習日期:2026-02-13

難度:Medium

類型:Tree、Binary Search Tree、Binary Tree

📘 題目敘述

給你一棵二元搜尋樹的根節點 root,以及一個整數 key

請你從 BST 中刪除值等於 key 的節點,並回傳更新後的根節點 root

刪除節點後,BST 的結構必須仍然有效。

你可以用任何方式回傳答案,只要結果仍是一棵有效的 BST 即可。

條件限制

  • 樹中節點的數量在範圍 [0, 10^4]
  • -10^5 <= Node.val <= 10^5
  • 樹中每個節點的值都互不相同
  • root 是一棵有效的 BST
  • -10^5 <= key <= 10^5

🧠 解題思路

這題我一樣先利用 BST 的性質去找到要刪的節點位置:

  • key < root->val 就代表要刪的節點只可能在左子樹
  • key > root->val 就代表只可能在右子樹
  • root->val == key 才進入真正的刪除處理

真正刪除時,BST 會遇到三種情況:

  1. 要刪的節點沒有左子樹
    代表它可以直接被右子樹取代
  2. 要刪的節點沒有右子樹
    代表它可以直接被左子樹取代
  3. 左右子樹都存在
    這種最麻煩,因為不能直接把其中一邊接上來,不然 BST 可能壞掉
    我的做法是找右子樹中最小的節點(也就是中序後繼 in-order successor)來頂替目前節點的值
    然後再去右子樹把那個「被拿來頂替的值」刪掉一次

這樣可以保證:

  • 目前節點的值會變成「比左子樹都大、又是右子樹裡最小」的合法值
  • 刪掉右子樹中的那個值後,整棵樹仍是 BST

所有變數

  • goal:當 root 同時有左右子樹時,我用它去找右子樹中最小的節點(中序後繼)

🪜 主要流程步驟

1. 先處理空樹

如果 root == nullptr,代表找不到要刪的節點,直接回傳 nullptr


2. 用 BST 性質往下找 key

如果目前節點不是要刪的值,就只會往一邊遞迴:

  • root->val > key:去左子樹刪,並把結果接回 root->left
  • root->val < key:去右子樹刪,並把結果接回 root->right

這樣遞迴回來時,整棵樹的連結也會被更新好。


3. 找到要刪的節點後,分三種刪除情況

如果 root->val == key,就進入刪除邏輯。


4. 沒有左子樹:直接用右子樹取代

如果 root->left 不存在,代表刪掉它後整棵樹要接回去的就是 root->right,所以直接回傳 root->right


5. 沒有右子樹:直接用左子樹取代

如果 root->right 不存在,同理直接回傳 root->left


6. 左右子樹都存在:用右子樹最小值頂替,再去刪掉那個值

這是核心步驟:

我先在右子樹找最左邊的節點:

  • goal = root->right
  • 一直 while (goal->left) goal = goal->left;

這樣 goal 就是右子樹裡最小的節點。

接著:

  • root->val = goal->val 用這個值取代目前節點的值
  • 但這樣會造成右子樹裡還存在一個相同的值,所以我再做一次:
  • root->right = deleteNode(root->right, goal->val)
  • 把右子樹裡那個 goal->val 的節點刪掉

最後 return root,整棵樹就會保持 BST 結構。

⏱️ 複雜度

  • 時間複雜度:O(h)
    h 是樹高。搜尋要刪的節點是 O(h),如果遇到「左右子樹都有」的情況,還會再往右子樹一路找最小值並再刪一次,但仍然都只走高度等級,所以整體是 O(h)。平衡 BST 是 O(log n),最壞鏈狀是 O(n)
  • 空間複雜度:O(h)
    主要是遞迴呼叫堆疊的深度。

💻 程式碼實作

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left),
 * right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (!root) {
            return nullptr;
        }
        if (root->val > key) {
            root->left = deleteNode(root->left, key);
        } else if (root->val < key) {
            root->right = deleteNode(root->right, key);
        } else {
            if (!root->left) {
                return root->right;
            } else if (!root->right) {
                return root->left;
            } else {
                TreeNode* goal = root->right;
                while (goal->left) {
                    goal = goal->left;
                }
                root->val = goal->val;
                root->right = deleteNode(root->right, goal->val);
            }
        }
        return root;
    }
};

https://leetcode.com/problems/delete-node-in-a-bst/

作者: scottnick
撰寫日期: 2026-02-13
類別:
原文連結: https://scottnick.github.io/cpp-notes/leetcode75/450-delete-node-in-a-bst.html