分治法 - 习题

1. 二叉树概述

1)定义:二叉树是每个节点最多有两个子树的树结构

2)种类

  • 空二叉树:根节点为null
  • 满二叉树 (Full):国内定义为,一个二叉树的每层的节点都达到最大值
  • 完全二叉树 (Complete):除最后一层外,其他各层节点数都达到最大个数,并且最后一层的所有节点都集中在左边
  • 平衡二叉树 (Balanced):左右子树的高度之差 <= 1,任意子树也必须是一颗平衡二叉树

2. 分治法

1)思路:将大规模问题拆分为若干个同类型子问题去处理的算法思想

2)应用

  • 二叉树:整棵树的左子树和右子树还是二叉树。
  • 数组:一个大数组可以拆分为若干不相交的子数组,例如快排、归排。

3)二叉树DFS的三种方式:前序,中序,后序

3. 相关例题

核心思路:遇到二叉树的问题,就想想整棵树在该问题上的结果,和左右子树在该问题上的结果之间有什么联系

3.1 二叉树上求值

LintCode 596 · 最小子树

思路:

  • 树的和 = 根节点值 + 左子树和 + 右子树和
  • 将最小子树和,以及对应的子树根节点设置为全局变量。
  • 利用分治的思想,递归求得各子树的和,并不断更新minSum和minRoot

LeetCode 236. 二叉树的最近公共祖先

要点:输入的两个点p和q是node object两个节点一定都在树中存在

思路:用递归的方法分情况讨论

  • 假设当前节点为null,则返回null
  • 假设当前节点为p或q,则返回当前节点root
  • 假设当前节点的左子树和右子树的返回值均不为null,则当前节点是最近公共祖先,返回root
  • 左子树或右子树的返回值不为null时,返回那个不为null的节点
  • 若以上情况都不满足,则返回null

 LintCode 578 · 最近公共祖先 III

要点:两个指定的节点不一定存在于树中

思路:相比于上一道题,需要两个额外信息,即a_exist和b_exist来表示是否找到点A和B。

  • 当前树是否有A = 左子树有A 或 右子树有A 或 当前节点为A
  • 当前树是否有B = 左子树有B 或 右子树有B 或 当前节点为B
  • 该题目的核心思路就是比上题多出两个点的flag
  • 最后返回结果时要判断A和B是否都存在

3.2 二叉树结构变化 

LeetCode 114. 二叉树展开为链表 

要点:DFS前序遍历这棵树,然后把结果一路向右串联起来

思路:树的链表 = 树的根节点 + 左子树的链表 + 右子树的链表

  • 如果想重组连接这三个部分,需要得到左右子树链表的头部节点和尾部节点。左右子树的头部节点可以由root.left和root.right获得。因此定义该递归函数,返回当前这棵树摊平后的尾部节点。
  • 如果左子树不为空,则需要重组root节点、左子树链表和右子树链表
  • 如果左子树为空,不需要重组,root.right连接的就是右子树链表

3.3 二叉查找树 Binary Search Tree

1)概述

  • 左子树节点的值 < 根节点的值 < 右子树节点的值
  • BST中的任意一个子树都是BST
  • 中序遍历结果有序,是非递减的

2)红黑树 Red-Black Tree

  • 红黑树是一种Balanced BST
  • Java的API实现 TreeMap / TreeSet
  • O(logN)的时间内实现增删查改;实现找最大最小

3)相关例题 LeetCode

108. 将有序数组转换为二叉搜索树701. 二叉搜索树中的插入操作700. 二叉搜索树中的搜索剑指 Offer II 055. 二叉搜索树迭代器

LeetCode 230. 二叉搜索树中第K小的元素

思路:

  • BST的中序遍历是有序的,非递减的
  • 因此采用二叉树中序遍历的非递归实现,找到答案停止,无需遍历完整棵树

LintCode 900 · 二叉搜索树中最接近的值

思路:该题的核心思想就是找到目标值最小上边界upperbound最大下边界lowerbound

  • 无优化的解法:中序遍历得到有序数组,然后进行二分查找
  • 优化解法:利用bst的左子树节点 < 根节点 < 右子树节点的特性,不断更新上下边界,从而找到最接近的值

LintCode 901 · 二叉搜索树中最接近的值 II

思路一:

  • 利用BST中序遍历的特性,得到一个有序列表list
  • 转化为在list上做二分法,找到离target最近的k个数
  • 时间复杂度为O(n)+O(logn)+O(k)

思路二:

  • 依然利用了BST中序遍历有序的特性,使用非递归实现二叉树的中序遍历 (保存根节点到当前节点的整条路径的实现方式)
  • 通过不断比较当前节点值与target,保存了一路走过的节点到两个栈lowerStack和upperStack里
  • 通过比较target离两个栈顶节点的值哪个更近,来将lowerStack挪动到prev node或将upperStack挪动到next node
  • 时间复杂度是O(h)+O(k)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值