算法(二)分而治之
算法(二)分而治之
1. 介绍
- 分而治之是算法设计中的一种方法
- 将一个问题分成多个和原问题相似的小问题,递归解决小问题,再将结果合并以解决原来的问题
场景一:归并排序
- 分:把数组从中间一分为二
- 解:递归地对两个子数组进归并排序
- 合:合并有序子数组
场景二:快速排序
- 分:选基准,按基准把数组分成两个子数组
- 解:递归地对两个子数组进行快速排序
- 合:对子数组进行合并
2. LeetCode题
374. 猜数字大小
解题思路:
- 二分搜索,同样具备“分、解、合”的特性
- 考虑选择分而治之
解题步骤:
- 分:计算中间元素,分割数组
- 解:递归地在较大或者较小子数组进行二分搜索
- 合:不需要刺不,因为在子数组中搜到就返回了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var guessNumber = function (n) { const rec = (low, high) => { if (low > high) return const mid = Math.floor((low + high) / 2) const res = guess(mid) if (res === 0) { return mid } else if (res === 1) { return rec(mid + 1, high) } else { return rec(1, mid - 1) } } return rec(1, n) };
|
226. 翻转二叉树
解题思路:
- 先翻转左右子树,再将子树换个位置
- 符合“分、解、合”特性
- 考虑选择分而治之
解题步骤:
- 分:获取左右子树
- 解:递归地翻转左右子树
- 合:将翻转后的左右子树换个位置放到根节点上
1 2 3 4 5 6 7 8
| var invertTree = function (root) { if (!root) return null; return { val: root.val, left: invertTree(root.right), right: invertTree(root.left) } };
|
100. 相同的树
解题思路:
- 两个树:根节点的值相同,左子树相同,右子树相同
- 符合“分、解、合”特性
- 考虑选择分而治之
解题步骤:
- 分:获取两个树的左子树和右子树
- 解:递归地判断两个树的左子树是否相同,右子树是否相同
- 合:将上述结果合并,如果根节点的值也相同,则树相同
1 2 3 4 5 6 7 8 9 10
| var isSameTree = function (p, q) { if (!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 };
|
101. 对称二叉树
解题思路:
- 转化为:左右子树是否镜像
- 分解为:树1的左子树和树2的右子树是否镜像,树1的右子树和树2的左子树是否镜像
- 符合“分、解、合”特性,考虑选择分而治之
解题步骤:
- 分:获取两个树的左子树和右子树
- 解:递归地判断树1和树2的右子树是否镜像,树1的右子树和树2的左子树是否镜像
- 合:如果上述都成了,且根节点值也相同,两个树就镜像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var isSymmetric = function (root) { if (!root) return true; const 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 } return false } return isMirror(root.left, root.right) };
|