【leetcode算法面试】leetcode题目3-树

 

题号题目说明
144Binary Tree Preorder Traversal二叉树先序遍历
94Binary Tree Inorder Traversal二叉树中序遍历
145Binary Tree Postorder Traversal二叉树后续遍历
95Unique Binary Search Trees II 独一无二的二叉搜索树之二 
96Unique Binary Search Trees 
98Validate Binary Search Tree 验证二叉搜索树

深度优先搜索 dfs

99Recover Binary Search Tree 复原二叉搜索树 
100Same Tree 判断相同树 
101Symmetric Tree 判断对称树 
102Binary Tree Level Order Traversal 二叉树层序遍历队列
104Maximum Depth of Binary Tree 二叉树的最大深度 
105Construct Binary Tree from Preorder and Inorder Traversal先序和中序遍历建立二叉树
108Convert Sorted Array to Binary Search Tree 将有序数组转为二叉搜索树二分思想
110Balanced Binary Tree 平衡二叉树 
111Minimum Depth of Binary Tree二叉树最小深度 
112Path Sum 二叉树的路径和 
113Path Sum II 
129

Sum Root to Leaf Numbers

求根到叶节点数字之和
226Invert Binary Tree 
235Lowest Common Ancestor of a Binary Search Tree

二叉搜索树的最小共同父节点

236Lowest Common Ancestor of a Binary Tree

二叉树的最小共同父节点

404Sum of Left Leaves求二叉树左叶子节点和
572Subtree of Another Tree判断一个树是另一个树的子树
700Search in a Binary Search Tree 

 

94. Binary Tree Inorder Traversal

    二叉树中序遍历

    递归方法:

func inorderTraversal(root *TreeNode) []int {
	var result []int
	return order(root, result)
}

func order(root *TreeNode, result []int) []int {
	if root == nil {
		return result
	}
	result = order(root.Left, result)
	result = append(result, root.Val)
	return order(root.Right, result)
}

      非递归

func inorderTraversal(root *TreeNode) []int {
	var result []int
	var stack = list.New()
	var t = root
	for t != nil || stack.Len() != 0 {
		for t != nil {
			stack.PushBack(t)
			t = t.Left
		}
		if stack.Len() != 0 {
			var val = stack.Back()
			var curNode = val.Value.(*TreeNode)
			result = append(result, curNode.Val)
			t = curNode.Right
			stack.Remove(val)
		}
	}
	return result
}

 

95. Unique Binary Search Trees II 独一无二的二叉搜索树之二

func generateTrees(n int) []*TreeNode {
	if n <= 0 {
		return nil
	}
	return genTrees(1, n)
}

func genTrees(start, end int) []*TreeNode {
	var subTree = make([]*TreeNode, 0)
	if start > end {
		subTree = append(subTree, nil)
	} else {
		for i:=start; i<=end; i++ {
			var leftSubTree = genTrees(start, i-1)
			var rightSubTree = genTrees(i+1, end)

			for j:=0; j<len(leftSubTree); j++ {
				for k:=0; k<len(rightSubTree); k++ {
					RootNode := &TreeNode{
						Val: i,
						Left: leftSubTree[j],
						Right: rightSubTree[k],
					}
					subTree = append(subTree, RootNode)
				}
			}
		}
	}
	return subTree
}

 

96. Unique Binary Search Trees

          二叉搜索树的性质为:在任一结点r的左(右)子树中,所有结点(若存在)均小于(大于)r。更一般性的特点是:任何一棵二叉树是二叉搜索树,当且仅当其中序遍历序列单调非降。

 

    Catalan Number卡特兰数的一个例子。卡特兰数的的递推公式:

 

98. [LeetCode] Validate Binary Search Tree 验证二叉搜索树

    根据二叉搜索树特性,左<根<右

  • 节点的左子树只包含小于当前节点的数。
  • 节点的右子树只包含大于当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。
func isValidBST(root *TreeNode) bool {
	const INT_MAX = int(^uint(0) >> 1)
	const INT_MIN = ^INT_MAX
	return validBST(root, INT_MIN, INT_MAX)
}

func validBST(root *TreeNode, left, right int) bool {
	if root == nil {
		return true
	}
	if root.Val <= left || root.Val >= right {
		return false
	}
	return validBST(root.Left, left, root.Val) && validBST(root.Right, root.Val, right)
}

 

99. Recover Binary Search Tree 复原二叉搜索树

func inorder(root *TreeNode, first, second, pre **TreeNode) {
	if root == nil {
		return
	}
	inorder(root.Left, first, second, pre)
	if (*pre).Val == -1 {
		*pre = root
	} else {
		if (*pre).Val > root.Val {
			if (*first).Val == -1 {
				*first = *pre
			}
			*second = root
		}
		*pre = root
	}
	inorder(root.Right, first, second, pre)
}
func recoverTree(root *TreeNode) {
	var first, second, pre = &TreeNode{Val: -1}, &TreeNode{Val: -1}, &TreeNode{Val: -1}
	if root == nil || (root.Left == nil && root.Right == nil) {
		return
	}
	inorder(root, &first, &second, &pre)
	first.Val, second.Val = second.Val, first.Val
}

 

101. [LeetCode] Symmetric Tree 判断对称树

     递归方法

func isSymmetric(root *TreeNode) bool {
	if root == nil {
		return true
	}
	return symmetric(root.Left, root.Right)
}

func symmetric(p, q *TreeNode) bool {
	if p == nil && q == nil {
		return true
	}

	if (p == nil && q != nil) || (p != nil && q == nil) || p.Val != q.Val {
		return false
	}
	return symmetric(p.Left, q.Right) && symmetric(p.Right, q.Left)
}

 

102. Binary Tree Level Order Traversal 二叉树层序遍历

func levelOrder(root *TreeNode) [][]int {
	var queue, res = list.New(), make([][]int, 0)
	if root == nil {
		return res
	}
	queue.PushBack(root)
	for queue.Len() != 0 {
		var n = queue.Len()
		var temp = make([]int, n)
		for i := 0; i < n; i++ {
			var val = queue.Front()
			var cur = val.Value.(*TreeNode)
			queue.Remove(val)
			if cur.Left != nil {
				queue.PushBack(cur.Left)
			}
			if cur.Right != nil {
				queue.PushBack(cur.Right)
			}
			temp[i] = cur.Val
		}
		res = append(res, temp)
	}
	return res
}

 

104. [LeetCode] Maximum Depth of Binary Tree 二叉树的最大深度

   递归方法,从根结点到叶结点依次经过的结点形成树的一条路径,最长路径的长度为树的深度。

   采用递归的方法,因为每个结点的这个子树的深度为,它的左右子树的深度中大的那一个加1,logn的时间复杂度,但是在树的深度过大时,会有栈溢出的问题

class Solution {
public:
    int maxDepth(TreeNode *root) {
        if (root == NULL)
            return 0;
        else {
            int x1 = maxDepth(root->left) + 1;
            int x2 = maxDepth(root->right) + 1;
            return (x1 > x2 ? x1 : x2);
        }
    }
};

 

111. Minimum Depth of Binary Tree二叉树最小深度

func min(a, b int) int {
	if a < b {return a}
	return b
}

func minDepth(root *TreeNode) int {
	if root == nil {return 0}
	if root.Left == nil {return 1+minDepth(root.Right)}
	if root.Right == nil {return 1+minDepth(root.Left)}
	return 1 + min(minDepth(root.Left), minDepth(root.Right))
}

 

105. Construct Binary Tree from Preorder and Inorder Traversal先序和中序遍历建立二叉树

    先序的顺序的第一个肯定是根,定位出根节点的位置,并以根节点的位置将中序遍历拆分为左右两个部分

func buildTree(preorder []int, inorder []int) *TreeNode {
	return build(preorder, 0, len(preorder)-1, inorder, 0, len(inorder)-1)
}

func build(preorder []int, pl, pr int, inorder []int, il, ir int) *TreeNode {
	if pl > pr || il > ir {return nil}
	var pos = 0
	for pos = il; pos <= ir; pos++ {
		if preorder[pl] == inorder[pos] {break}
	}
	var cur = &TreeNode{Val: preorder[pl]}
	cur.Left = build(preorder, pl+1, pl +pos-il, inorder, il, pos-1)
	cur.Right = build(preorder, pl+pos-il+1, pr, inorder, pos+1, ir)
	return cur
}

 

108. Convert Sorted Array to Binary Search Tree 将有序数组转为二叉搜索树

     左<根<右,根节点应该是有序数组的中间点,从中间点分开为左右两个有序数组,在分别找出其中间点作为原中间点的左右两个子节点,二分查找

func sortedArrayToBST(nums []int) *TreeNode {
	return sortedToBST(nums, 0, len(nums)-1)
}
func sortedToBST(nums []int, start, end int) *TreeNode {
	if start > end {return nil}
	var mid = (start + end) / 2
	var root = &TreeNode{Val: nums[mid]}
	root.Left = sortedToBST(nums, start, mid-1)
	root.Right = sortedToBST(nums, mid+1, end)
	return root
}

 

110. Balanced Binary Tree 平衡二叉树

func maxInt(a, b int) int {
	if a > b {return a}
	return b
}

func abs(a, b int) int {
	if a > b {return a-b}
	return b-a
}

func isBalanced(root *TreeNode) bool {
	if root == nil {return true}
	var left = height(root.Left)
	var right = height(root.Right)
	if abs(left, right) > 1 {return false}
	return isBalanced(root.Left) && isBalanced(root.Right)
}

func height(root *TreeNode) int {
	if root == nil {return 0}
	return 1 + maxInt(height(root.Left), height(root.Right))
}

 

144. Binary Tree Preorder Traversal

     递归方法

func preorderTraversal(root *TreeNode) []int {
	var ret []int
	return preorder(root, ret)
}

func preorder(root *TreeNode, ret []int) []int {
	if root == nil {
		return ret
	}

	ret = append(ret, root.Val)
	ret = preorder(root.Left, ret)
	return preorder(root.Right, ret)
}

     非递归方法

func preorderTraversal(root *TreeNode) []int {
	var ret []int
	var stack = list.New()
	var t = root
	for t != nil || stack.Len() != 0 {
		for t != nil {
			ret = append(ret, t.Val)
			stack.PushBack(t)
			t = t.Left
		}
		if stack.Len() != 0 {
			var val = stack.Back()
			var curNode = val.Value.(*TreeNode)
			t = curNode.Right
			stack.Remove(val)
		}
	}
	return ret
}

 

145. Binary Tree Postorder Traversal

    后序遍历

    递归方法

func postorderTraversal(root *TreeNode) []int {
	var ret []int
	return postorder(root, ret)
}

func postorder(root *TreeNode, ret []int) []int {
	if root == nil {
		return ret
	}

	ret = preorder(root.Left, ret)
	ret = preorder(root.Right, ret)
    ret = append(ret, root.Val)
    return ret
}

    非递归非方法

func postorderTraversal(root *TreeNode) []int {
	var ret []int
	var stack = list.New()
	var pre *TreeNode

	if root != nil {
		stack.PushBack(root)
	}

	for stack.Len() != 0 {
		val := stack.Back()
		cur := val.Value.(*TreeNode)
		if pre == nil || pre.Left == cur || pre.Right == cur {
			if cur.Left != nil {
				stack.PushBack(cur.Left)
			} else if cur.Right != nil {
				stack.PushBack(cur.Right)
			}
		} else if cur.Left == pre {
			if cur.Right != nil {
				stack.PushBack(cur.Right)
			}
		} else {
			ret = append(ret, cur.Val)
			stack.Remove(val)
		}
		pre = cur
	}

	return ret
}

 

129. [LeetCode] Sum Root to Leaf Numbers

func sumNumbers(root *TreeNode) int {
        return sumTree(root, 0)
}

func sumTree(root *TreeNode, sum int) int {
        if root == nil {
                return sum 
        }
        var curr = sum*10 + root.Val
         
        if root.Left == nil && root.Right == nil {
                return curr
        }
         
        var left, right = 0, 0
        if root.Left != nil {
                left = sumTree(root.Left, curr)
        }
        if root.Right != nil {
                right = sumTree(root.Right, curr)
        }
         
        return left + right
}

     递归到该点的时候就把这点的值与前面的值乘以10,然后相加

func sumNumbers(root *TreeNode) int {
	return sumTree(root, 0)
}

func sumTree(root *TreeNode, sum int) int {
	if root == nil {
		return 0
	}

	var curr = sum*10 + root.Val
	if root.Left == nil && root.Right == nil {
		return curr
	}

	return sumTree(root.Left, curr) + sumTree(root.Right, curr)
}

    递归方法

func isSameTree(p *TreeNode, q *TreeNode) bool {
	if p == nil && q == nil {
		return true
	}

	if  (p == nil && q != nil) || (p != nil && q == nil) ||  p.Val != q.Val {
		return false
	}

	return isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)
}

 

112. Path Sum 二叉树的路径和

       深度优先算法DFS的思想来遍历每一条完整的路径,也就是利用递归不停找子节点的左右子节点,而调用递归函数的参数只有当前节点和sum值。

func hasPathSum(root *TreeNode, sum int) bool {
	if root == nil {
		return false
	}
	if root.Left == nil && root.Right == nil && root.Val == sum {
		return true
	}
	return hasPathSum(root.Left, sum - root.Val) || hasPathSum(root.Right, sum - root.Val)
}

 

113. Path Sum II

      每当DFS搜索到新节点时,都要保存该节点。而且找出一条路径之后,保存到最终结果二位vector中。每当DFS搜索到子节点,发现不是路径和时,返回上一个结点时,需要把该节点从一维vector中移除 

func pathSum(root *TreeNode, sum int) [][]int {
	var cur = make([]int, 0)
	var ret [][]int
	path(root, sum, cur, &ret)
	return ret
}

func path(root *TreeNode, sum int, cur []int, ret *[][]int) {
	if root == nil {
		return
	}

	cur = append(cur, root.Val)
	if sum == root.Val && root.Left == nil && root.Right == nil {
		res := make([]int, len(cur))
		copy(res, cur)
		*ret = append(*ret, res)
	}
	path(root.Left, sum-root.Val, cur, ret)
	path(root.Right, sum-root.Val, cur, ret)
	if len(cur) > 0 {
		cur = cur[:len(cur)-1]
	}
}

 

226. Invert Binary Tree

func invertTree(root *TreeNode) *TreeNode {
	if root == nil {
		return nil
	}
	var temp = root.Left
	root.Left = invertTree(root.Right)
	root.Right = invertTree(temp)
	return root
}

 

404. Sum of Left Leaves

      求一棵二叉树的所有左子叶的和,需要知道当前结点是否是左子节点,如果是左子节点,而且该左子节点再没有子节点了说明其是左子叶,那么我们将其值加入结果res中,我们用一个bool型的变量,如果为true说明当前结点是左子节点,若为false则说明是右子节点,不处理

func sumOfLeftLeaves(root *TreeNode) int {
	if root == nil || (root.Left==nil  && root.Right==nil) {
		return 0
	}
	var ret = 0
	sumLeft(root.Left, true, &ret)
	sumLeft(root.Right, false, &ret)
	return ret
}

func sumLeft(root *TreeNode, left bool, ret *int) {
	if root == nil {
		return
	}
	if left && root.Left == nil && root.Right == nil {
		*ret += root.Val
	}
	sumLeft(root.Left, true, ret)
	sumLeft(root.Right, false, ret)
}

 

572. Subtree of Another Tree

      从s的根结点开始,跟t比较,如果两棵树完全相同,那么返回true,否则就分别对s的左子结点和右子结点调用递归再次来判断是否相同

func isSubtree(s *TreeNode, t *TreeNode) bool {
	if s == nil {
		return false
	}
	if isSameTree(s, t) {
		return true
	}
	return isSubtree(s.Left, t) || isSubtree(s.Right, t)
}

func isSameTree(s *TreeNode, t *TreeNode) bool {
	if s == nil && t == nil {
		return true
	}
	if (s == nil && t != nil) || (s != nil && t == nil) || s.Val != t.Val {
		return false
	}
	return isSameTree(s.Left, t.Left) && isSameTree(s.Right, t.Right)
}

 

700. Search in a Binary Search Tree

     左<根<右。那么就是说任意一个结点的左子树中的所有结点均小于当前结点,其右子树中的所有结点均大于当前结点

func searchBST(root *TreeNode, val int) *TreeNode {
	if root == nil {
		return nil
	}
	if root.Val == val {
		return root
	} else if root.Val > val{
		return searchBST(root.Left, val)
	} else {
		return searchBST(root.Right, val)
	}
}

 

235. Lowest Common Ancestor of a Binary Search Tree

func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
	if root == nil {
		return nil
	}
	min := func(one, two int) int {
		if one < two {
			return one
		}
		return two
	}
	max := func(one, two int) int {
		if one > two {
			return one
		}
		return two
	}

	if root.Val < min(p.Val, q.Val) {
		return lowestCommonAncestor(root.Right, p, q)
	} else if root.Val > max(p.Val, q.Val) {
		return lowestCommonAncestor(root.Left, p, q)
	} else {
		return root
	}
}

 

236. Lowest Common Ancestor of a Binary Tree

当前结点是否为空,或者为p或q中的任意一个

若p和q要么分别位于左右子树中,那么对左右子结点调用递归函数,会分别返回p和q结点的位置

 

func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
	if root == nil || p == root || q == root {
		return root
	}
	var left = lowestCommonAncestor(root.Left, p, q)
	var right = lowestCommonAncestor(root.Right, p, q)

	if left != nil && right != nil {
		return root
	}
	if left != nil {
		return left
	}
	return right
}

 

1. 判断一个树是否平衡二叉树

    如果某个二叉树中任意结点的左右子树的深度相差不超过1,那么他就是一棵平衡二叉树。
    首先可以采用递归的方法来计算每一个结点的深度,需要递归计算它的左右子树的深度,当返回的左右的子树的深度差大于1时就不是平衡二叉树了。

int highTree(TreeNode* root) {
    if(root==NULL) return 0;
    int L=0, R=0;
    if(root->left)
       L=highth(root->left);
    if(root->right)
       R=highth(root->right);
    if(L-R>1||R-L>1)
       flag=0;
    return max(L,R)+1;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值