LeetCode0654: 最大二叉树

题目介绍

描述:

给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:

二叉树的根是数组中的最大元素。 左子树是通过数组中最大值左边部分构造出的最大二叉树。 右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构建最大二叉树,并且输出这个树的根节点。

输入:[3,2,1,6,0,5]
输出:返回下面这棵树的根节点:

      6
    /   \\
   3     5
    \\    / 
     2  0   
       \\
        1

提示:

  1. 给定的数组的大小在 [1, 1000] 之间。

解题思路:

递归算法的关键是要明确函数的「定义」是什么,然后相信这个定义,利用这个定义推导最终结果。

写树相关的算法,简单说就是,先搞清楚当前 root 节点该做什么,然后根据函数定义递归调用子节点,递归调用会让孩子节点做相同的事情。

二叉树题目的一个难点在于如何通过题目的要求思考出每一个节点需要做什么

判断当前root节点,如果nums是空(按题目提示,不会出现这个情况)或者长度为1,则好判断。其他情况下root.val = max(nums),然后依次对左半边和右半边进行递归调用。但是实际写代码的时候出错了。

自己的解法实现

def constructMaximumBinaryTree2(self, nums):
        if not nums: return None
        max_data = max(nums)
        index = nums.index(max_data)
        left_list = nums[:index]
        right_list = nums[index + 1:]

        root = TreeNode(max_data)
        root.left = self.constructMaximumBinaryTree(left_list)
        root.right = self.constructMaximumBinaryTree(right_list)

        return root

网上比较优秀的解法

解法一

和我的类似,不过是多了一个辅助函数

def constructMaximumBinaryTree2(self, nums):
        def construct(nums):
            if not nums: return
            node = TreeNode(max(nums))
            index = nums.index(max(nums))
            node.left = construct(nums[:index])
            node.right = construct(nums[index + 1:])
            return node

        return construct(nums)

解法二

没太看懂

def dfs(i, j):
            import sys
            if i >= j: return None
            idx = -1
            val = -sys.maxsize
            for k in range(i, j):
                if nums[k] > val:
                    val = nums[k]
                    idx = k
            node = TreeNode(val)
            node.left = dfs(i, idx)
            node.right = dfs(idx + 1, j)
            return node

        return dfs(0, len(nums))

解法三

def constructMaximumBinaryTree4(self, nums):
        if not nums: return None
        m, k = nums[0], 0
        for i in range(len(nums)):
            if nums[i] > m:
                m, k = nums[i], i
        node = TreeNode(m)
        node.left = self.constructMaximumBinaryTree4(nums[:k])
        node.right = self.constructMaximumBinaryTree4(nums[k + 1:])
        return node

解法四

递归方法。 为加快查询速度,在最开始定义了字典d。 字典d记录了每个nums内现有的数字所在的检索位置 这个检索方法比nums.index(maxvalue)来的快 (因为字典d是用hash表的方式存储速度)

def constructMaximumBinaryTree5(self, nums):
        n = len(nums)
        index = [x for x in range(n)]
        d = dict(zip(nums, index))
        return self.createNode(nums, 0, n - 1, d)

    def createNode(self, nums, start, end, d):
        # nums 原数组,start 指向数组开始,end指向结束
        rootvalue = max(nums[start: end + 1])
        index = d[rootvalue]
        root = TreeNode(rootvalue)
        if start == end:
            return root
        if not index == start:  # 左侧如果还有值
            root.left = self.createNode(nums, start, index - 1, d)
        if not index == end:
            root.right = self.createNode(nums, index + 1, end, d)
        return root

解法五

建立单调栈, 当前元素大于栈顶元素时, 将栈顶元素作为当前元素的右子节点并出栈, 直到栈空或者栈顶元素大于当前值 当前值新建节点入栈

def constructMaximumBinaryTree6(self, nums):
        st, pre, N = [], None, len(nums)
        MAX = pow(2, 31)
        for i in range(0, N + 1):
            pivot = MAX if i==N else nums[i]
            pre = None
            while len(st) > 0 and st[-1].val < pivot:
                st[-1].right = pre
                pre = st.pop(-1)
            node = TreeNode(pivot)
            node.left = pre
            st.append(node)
        return pre

相关知识总结和思考

相关知识:

  • 队列是先进先出(FIFO, First-In-First-Out)的线性表,只允许在后端(称为rear)进行插入操作,在前端(称为front)进行删除操作。
  • 栈是限定仅在表头进行插入和删除操作的线性表

典型的递归问题,依然按照递归三部曲来分析:

  • 确定递归函数的参数和返回值
  • 确定终止条件
  • 确定单层递归的逻辑

你可能感兴趣的:(LeetCode0654: 最大二叉树)