代码随想录算法训练营 Day 16

2 minute read

Published:

Q1. LeetCode 530

思路 - 中序遍历

二叉搜索树保证了左<中<右

解法1. 递归法(获得遍历结果然后计算最小值)

class Solution:
    def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
        arr = []
        def dfs(node):
            if not node:
                return
            dfs(node.left)
            arr.append(node.val)
            dfs(node.right)
        
        dfs(root)

        res = float('inf')
        for i in range(1, len(arr)):
            res = min(res, arr[i] - arr[i - 1])
        
        return res

解法2: 递归法(遍历过程中统计最小值)

class Solution:
    def __init__(self):
        self.res = float('inf')
        self.pre = None

    def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
        if not root:
            return

        self.getMinimumDifference(root.left)
        if self.pre:
            self.res = min(self.res, root.val - self.pre.val)
        self.pre = root

        self.getMinimumDifference(root.right)

        return self.res

解法3: 迭代法

class Solution:
    def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
        res = float('inf')
        prev = None
        stack = [root]
        
        while stack:
            curr = stack.pop()
            if curr:
                if curr.right:
                    stack.append(curr.right)
                
                stack.append(curr)
                stack.append(None)

                if curr.left:
                    stack.append(curr.left)
            else:
                curr = stack.pop()
                if prev:
                    res = min(res, curr.val - prev.val)
                prev = curr
        
        return res

Q2. LeetCode 501

解法1: 通过任何遍历方式,统计每个元素出现的次数(非二叉搜索树的解决方法)

class Solution:
    def findMode(self, root: Optional[TreeNode]) -> List[int]:
        arr = defaultdict(int)
        def dfs(node):
            if not node:
                return

            arr[node.val] += 1
            dfs(node.left)
            dfs(node.right)
        
        if not root:
            return []
        
        dfs(root)
        res = []
        max_freq = max(arr.values())
        for num, freq in arr.items():
            if freq == max_freq:
                res.append(num)
        
        return res 

解法2: 二叉搜索树的性质决定当使用中序遍历时,只需要比较当前节点和之前节点是否相同。通过max_freq变量统计当前最大频率,因此不需要额外的空间开销

注意:max_freq可能会随着遍历而修改,在每次修改的过程中,需要将之前的结果数组清空

class Solution:
    def __init__(self):
        self.res = []
        # 统计当前的最大频率
        self.max_freq = 0
        self.prev = None
        self.count = 0

    def findMode(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return

        self.findMode(root.left)
        if not self.prev:
            self.count = 1
        elif root.val == self.prev.val:
            self.count += 1
        else:
            self.count = 1
        self.prev = root

        if self.count == self.max_freq:
            self.res.append(root.val)
        
        if self.count > self.max_freq:
            self.max_freq = self.count
            self.res = [root.val]
        
        self.findMode(root.right)

        return self.res

解法3: 迭代法

class Solution:
    def findMode(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []
        
        res = []
        stack = [root]
        prev = None
        max_freq = 0
        count = 0

        while stack:
            curr = stack.pop()
            if curr:
                if curr.right:
                    stack.append(curr.right)
                
                stack.append(curr)
                stack.append(None)

                if curr.left:
                    stack.append(curr.left)
            else:
                curr = stack.pop()

                if not prev:
                    count = 1
                elif curr.val == prev.val:
                    count += 1
                else:
                    count = 1
                prev = curr
                
                if count > max_freq:
                    max_freq = count
                    res = []

                if count == max_freq:
                    res.append(curr.val)

        return res

Q3. LeetCode 236

思路 - 后序遍历

先在左右子树中分别寻找匹配项,在中间节点根据返回结果求解

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        def dfs(node):
            if not node:
                return None
            if node == p or node == q:
                return node
            
            # 左右节点
            l = dfs(node.left)
            r = dfs(node.right)

            # 中间节点
            # 在左子树和右子树中找到了p和q - 返回当前节点
            if l and r:
                return node
            # 只在右子树中找到匹配项 - 返回有节点
            elif not l and r:
                return r
            elif not r and l:
                return l
            
            return None

        res = dfs(root)

        return res  

Take some notes

  1. 求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式。

  2. 在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的l和r)做逻辑判断。

  3. 代码中包含了最小公共祖先为其中某个节点的特殊情况(第二个if判断条件)