【Lintcode】python - [901] Closest Binary Search Tree Value II 個人解法筆記 #綜合難題

題目出處

901 · Closest Binary Search Tree Value II

難度

hard

個人範例程式碼

from typing import (
    List,
)
from lintcode import (
    TreeNode,
)

"""
Definition of TreeNode:
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left, self.right = None, None
"""

class Solution:
    """
    @param root: the given BST
    @param target: the given target
    @param k: the given k
    @return: k values in the BST that are closest to the target
             we will sort your return value in output
    """
    def closest_k_values(self, root: TreeNode, target: float, k: int) -> List[int]:
        if not root or k == 0:
            return []

        # write your code here
        lower_stack = self.get_stack(root, target) # init to found target
        upper_stack = list(lower_stack)

        # delete duplicate closest element, change wrong lower[-1] or upper[-1]
        if lower_stack[-1].val < target:
            self.move_upper(upper_stack)
        else:
            self.move_lower(lower_stack)

        ans = []
        for i in range(k):
            if self.is_lower_closer(lower_stack, upper_stack, target):
                ans.append(lower_stack[-1].val)
                self.move_lower(lower_stack)
            else:
                ans.append(upper_stack[-1].val)
                self.move_upper(upper_stack)
        return ans

    def is_lower_closer(self, lower_stack, upper_stack, target):
        if not lower_stack: # has nothing
            return False
        if not upper_stack:
            return True

        return target - lower_stack[-1].val < upper_stack[-1].val - target

    def move_lower(self, stack):
        if stack[-1].left: # has left, move to the right bottom
            node = stack[-1].left
            while node:
                stack.append(node)
                node = node.right
        else: # no left, move to the first turn right parent
            node = stack.pop()
            while stack and stack[-1].left == node:
                node = stack.pop()

    def move_upper(self, stack):
        if stack[-1].right: # has right, move to the left bottom
            node = stack[-1].right
            while node:
                stack.append(node)
                node = node.left
        else: # no right, move to the first turn left parent
            node = stack.pop()
            while stack and stack[-1].right == node:
                node = stack.pop()

    def get_stack(self, root, target):
        stack = []
        while root:
            stack.append(root)
            if target <= root.val:
                root = root.left
            else:
                root = root.right

        return stack

算法說明

BST iteration 集大成的最難題目,能考的都考了。

這題最難的部分在於實作 iteration (當然,要重新 traverse 絕對是更簡單的方法,不過速度上會慢),

分成兩種狀況討論:

  • 往更小「一個」移動
  • 往更大「一個」移動

往更小「一個」移動

說到小,就先想到 left

這裡又分成兩種情況,

  • 如果有 left,往 left 的 最右底點移動 (才會是「第一個」更小)
  • 如果沒有 left,找第一個 edge 右彎的 parent

看不懂就看下圖可能會比較好懂… 一點點XD

往更大「一個」移動

說到大,就先想到 right

這裡又分成兩種情況,

  • 如果有 right,往 right 的 最左底點移動 (才會是「第一個」更大)
  • 如果沒有 right,找第一個 edge 左彎的 parent

看不懂就看下圖可能會比較好懂… 一點點XD

最近在練習程式碼本身就可以自解釋的 Coding style,可以嘗試直接閱讀程式碼理解

input handling

當 k = 0 或是沒有 root 時,return []

Boundary conditions

見上述說明

Reference