• 边工作边刷题:70天一遍leetcode: day 82-1


    Closest Binary Search Tree Value II

    要点:通过iterator,把closest值附近的k个closest找到,从而time降为O(klgn)

    • in order iterator的本质:栈存当前见到,未来还要再访问到的node。当前见到是沿着left访问,而未来再见到就是到了right branch
    • 这题的iterator实现和一般的in-order iterator略有不同:inorder访问后的结点并不出栈而是直接继续push right subtree,当右子pop的时候,继续通过判断是否为右子决定是否pop父节点。如果是左子,那么父节点。而一般的iterator实现不需要连续验证父节点,因为在push right subtree之前已经出栈了。
    • 这题之所以不pop父节点是因为初始化(小就向左大就向右)后的stack状态和以当前点iterator的stack state是一样的,而向右走是不pop的。
    • 初始化和I的区别:最后只保留closest之前的在栈里,但是在完整路径走完之前是不知道的。所以只能最后截取。

    https://repl.it/Cg9u/2 (scott solution)
    https://repl.it/CiYU/2 (my)
    错误点

    • cur1和cur2有可能过界,因为是超过一边的比较,但不会2个都过界。所以条件是not cur2 OR (cur1 and dist(cur1)<dist(cur2)
    def closestKValues(self, root, target, k):
    
        # Helper, takes a path and makes it the path to the next node
        def nextpath(path, kid1, kid2):
            if path:
                if kid2(path):
                    path += kid2(path), # 当前node(右子)进栈
                    while kid1(path):
                        path += kid1(path), 
                else:
                    kid = path.pop()
                    while path and kid is kid2(path):
                        kid = path.pop()
    
        # These customize nextpath as forward or backward iterator
        kidleft = lambda path: path[-1].left
        kidright = lambda path: path[-1].right
    
        # Build path to closest node
        path = []
        while root:
            path += root,
            root = root.left if target < root.val else root.right
        dist = lambda node: abs(node.val - target)
        path = path[:path.index(min(path, key=dist))+1]
    
        # Get the path to the next larger node
        path2 = path[:]
        nextpath(path2, kidleft, kidright)
    
        # Collect the closest k values by moving the two paths outwards
        vals = []
        for _ in range(k):
            if not path2 or path and dist(path[-1]) < dist(path2[-1]):
                vals += path[-1].val, # 当所有左子都访问后,如果当前点是父节点的右子,其为栈顶,在这里访问,之后如果其没右子,就被pop掉。和一般的iterator算法有什么不同?这里左子树访问完了的结点是不出栈的直接push右节点,当右子树访问完了... next: 右子访问结束呢? 所以要连续pop右子,这样可以保证不会再进到右子。而左子只会把自己pop掉,露出父结点
                nextpath(path, kidright, kidleft)
            else:
                vals += path2[-1].val,
                nextpath(path2, kidleft, kidright)
        return vals
            
    
    # Given a non-empty binary search tree and a target value, find k values in the BST that are closest to the target.
    
    # Note:
    # Given target value is a floating point.
    # You may assume k is always valid, that is: k ≤ total nodes.
    # You are guaranteed to have only one unique set of k values in the BST that are closest to the target.
    # Follow up:
    # Assume that the BST is balanced, could you solve it in less than O(n) runtime (where n = total nodes)?
    
    # Hint:
    
    # Consider implement these two helper functions:
    # getPredecessor(N), which returns the next smaller node to N.
    # getSuccessor(N), which returns the next larger node to N.
    # Try to assume that each node has a parent pointer, it makes the problem much easier.
    # Without parent pointer we just need to keep track of the path from the root to the current node using a stack.
    # You would need two stacks to track the path in finding predecessor and successor node separately.
    # Hide Company Tags Google
    # Hide Tags Tree Stack
    # Hide Similar Problems (M) Binary Tree Inorder Traversal (E) Closest Binary Search Tree Value
    
    # Definition for a binary tree node.
    # class TreeNode(object):
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution(object):
        def closestKValues(self, root, target, k):
            """
            :type root: TreeNode
            :type target: float
            :type k: int
            :rtype: List[int]
            """
            def next(stk, left, right):
                top = stk[-1]
                if right(top):
                    l = right(top)
                    while l:
                        stk.append(l)
                        l=left(l)
                    return stk[-1]
                else:
                    top = stk.pop()
                    while stk and right(stk[-1])==top:
                        top = stk.pop()
                    return stk[-1] if stk else None # error: doesnt matter, will never be empty
            
            left = lambda x: x.left
            right = lambda x: x.right
            
            stk = []
            while root:
                stk.append(root)
                if root.val<target:
                    root = root.right
                else:
                    root = root.left
            # print [s.val for s in stk]
            
            dist = lambda x: abs(x.val-target)
            stk1 = stk[:stk.index(min(stk, key=dist))+1] # error 1: how to get min and keep the index
            stk2 = list(stk1)
            
            cur1 = stk1[-1]
            cur2 = next(stk2, left, right)
            res = []
            
            for _ in xrange(k):
                if not cur2 or (cur1 and dist(cur1)<dist(cur2)): # error
                    res.append(cur1.val)
                    cur1 = next(stk1, right, left)
                else:
                    res.append(cur2.val)
                    cur2 = next(stk2, left, right)
            
            return res
    
    
  • 相关阅读:
    斐波那契数
    组合数学
    网络流
    UVA 1104 【芯片难题 Chips Challenge】
    Luogu P3181 【[HAOI2016]找相同字符】
    Luogu P4101 【[HEOI2014]人人尽说江南好 】
    Luogu P5842 【[SCOI2012]Blinker 的仰慕者】
    BZOJ 4502 串
    Luogu P5840 【[COCI2015]Divljak】
    Luogu P3295 【[SCOI2016]萌萌哒】
  • 原文地址:https://www.cnblogs.com/absolute/p/5815728.html
Copyright © 2020-2023  润新知