- 分而治之是算法设计中的一种方法
它将一个问题分为多个和原问题相似的小问题,递归解决小问题,再将结果合并易解决原来的问题
场景
1.归并排序
分:把数组从中间一分为二
- 解:递归地对两个子数组进行归并排序
-
2.快速排序
分:选基准,按照基准把数组分成两个子数组
- 解:递归地对两个子数组进行快速排序
- 合:对两个子数组进行合并
题目
1.猜数字大小 - 374
```javascript /**- Forward declaration of guess API.
- @param {number} num your guess
- @return -1 if num is lower than the guess number
- 1 if num is higher than the guess number
- otherwise return 0
- var guess = function(num) {} */
/**
- @param {number} n
- @return {number}
*/
var guessNumber = function(n) {
// 定义递归函数
const rec = (low, high) => {
} // 返回递归结果 return rec(1, n) }; ```// 递归终止条件,当最小值大于最大值if(low > high) { return }// 取中间的值const mid = Math.floor((low + high) /2)// 拿到猜的结果const res = guess(mid)if(res === 0) {return mid} else if( res === -1){// 如果猜的值比mid小// 就继续递归搜索,并把范围缩小一半return rec(low, mid -1)} else {// 如果猜的值比mid大return rec(mid + 1,high)}
2.翻转二叉树
翻转一棵二叉树。
示例:
输入:
4
/ \
2 7
/ \ / \
1 3 6 9
输出:
4
/ \
7 2
/ \ / \
9 6 3 1
思路:
- 先翻转左右子树,再将子树换个位置
- 也符合“分、解、合”的特性
- 考虑使用分而治之
解题步骤:
- 分:获取左右子树
- 解:递归地的翻转左右子树
- 合:将翻转后的左右子树换个位置放到根节点上
/*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val = (val===undefined ? 0 : val)* this.left = (left===undefined ? null : left)* this.right = (right===undefined ? null : right)* }*//*** @param {TreeNode} root* @return {TreeNode}*/var invertTree = function(root) {// 递归结束条件if(!root) return null// 递归地翻转树的左右节点return {val: root.val,left: invertTree(root.right),right: invertTree(root.left)}};
3.相同的树 - 100
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入:p = [1,2,3], q = [1,2,3]
输出:true
示例 2:
输入:p = [1,2], q = [1,null,2]
输出:false
示例 3:
输入:p = [1,2,1], q = [1,1,2]
输出:false
提示:
- 两棵树上的节点数目都在范围 [0, 100] 内
- -104 <= Node.val <= 104
思路:
- 两个树:根节点的值相同,左子树相同,右子树相同
- 符合“分、解、合”的思路
解题步骤:
- 分:获取两个树的左子树合右子树
- 解:递归判断两个树的左子树是否相同、右子树是否相同
- 合:将上述结果合并,如果根节点的值也相同,树就相同
/*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val = (val===undefined ? 0 : val)* this.left = (left===undefined ? null : left)* this.right = (right===undefined ? null : right)* }*//*** @param {TreeNode} p* @param {TreeNode} q* @return {boolean}*/var isSameTree = function(p, q) {// 排除特殊的空树,返回trueif (!p && !q) return true// 判断根节点的值if(p && q && p.val === q.val &&// 判断左右节点是否相同isSameTree(p.left, q.left) &&isSameTree(p.right, q.right)) {return true}return false};
- 时间复杂度:O(N - 树的节点数)
- 空间复杂度:最坏:O(N - 树的节点数) 最好:O(logN) 均匀分布
4.对称二叉树 - 101
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1<br /> / \<br /> 2 2<br /> / \ / \<br />3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1<br /> / \<br /> 2 2<br /> \ \<br /> 3 3<br /> <br />进阶:<br />你可以运用递归和迭代两种方法解决这个问题吗?
思路:
- 转化为:左右子树是否镜像
- 分解为:树1的左子树是否和树2的右子树是否是镜像的,树1的右子树是否和树2的左子树是否是镜像的
- 符合“分、解、合”,考虑分而治之
解题步骤:
- 分:获取两个树的左子树和右子树
- 解:递归的判断树1的左子树是否和树2的右子树是否是镜像的,树1的右子树是否和树2的左子树是否是镜像的
- 合:如果上述成立,且根节点值相同,则树为镜像的树
/*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val = (val===undefined ? 0 : val)* this.left = (left===undefined ? null : left)* this.right = (right===undefined ? null : right)* }*//*** @param {TreeNode} root* @return {boolean}*/var isSymmetric = function(root) {// 处理特殊用例if(!root) return trueconst isMirror = (l, r) => {// 递归终点if(!l && !r) return true// 判断根节点是否相同if(l && r && l.val === r.val &&// 递归地判断左子树和右子树是否镜像isMirror(l.left, r.right) &&isMirror(l.right, r.left)) {// 是镜像return true}// 否则返回falsereturn false}// 返回return isMirror(root.left, root.right)};
