⑫ 算法设计思想之“分而治之”
一、理论
1. 简介
- 分而治之是 算法设计 中的一种方法
- 它将一个问题 分 成多个和原问题相似的小问题, 递归解决 小问题,再将结果 合 并以解决原来的问题
2. 场景
2.1 归并排序
- 分:把数组从中间一分为二
- 解:递归地对两个子数组进行归并排序
- 合:合并有序子数组
2.2 快速排序
- 分:选基准,按基准把数组分成两个子数组
- 解:递归地对两个子数组进行快速排序
- 合:对两个子数组进行合并
二、刷题
1. 猜数字大小(374)
1.1 题目描述
- 猜数字游戏的规则如下:
- 每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
- 如果你猜错了,我会告诉你,你猜测的数字比我选出的数字是大了还是小了。
- 你可以通过调用一个预先定义好的接口 int guess(int num) 来获取猜测结果,返回值一共有 3 种可能的情况(-1,1 或 0):
- -1:我的数字比较小 pick < num
- 1:我的数字比较大 pick > num
- 0:恭喜!你猜对了!pick == num
1.2 解题思路
- 二分搜索,同样具备“分解合”的特性
- 考虑选择分而治之
1.3 解题步骤
- 分:计算中间元素,分割数组
- 解:递归地在较大或较小子数组进行二分搜索
function guessNumber(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 if(res === -1) {
return rec(1, mid-1)
}
}
return rec(1, n)
}
1.4 时间复杂度&空间复杂度
- 时间复杂度:O(logn)
- 空间复杂度:O(n)
2. 翻转二叉树(226)
2.1 题目描述
- 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点
2.2 解题思路
- 先翻转左右子树,再将子树换个位置
- 符合 “分 解 合” 特性
2.3 解题步骤
- 分:获取左右子树
- 解:递归地翻转左右子树
- 合:将翻转后的左右子树换个位置放到根节点上
function invertTree(root) {
if(!root) return null
return {
val: root.val,
right: invertTree(root.left),
left: invertTree(root.right)
}
}
2.4 时间复杂度&空间复杂度
- 时间复杂度:O(n)
- 空间复杂度:O(n)
3. 相同的树(100)
3.1 题目描述
- 给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同
- 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的
3.2 解题思路
输入:p = [1,2,3], q = [1,2,3]
输出:true
- 两个树:根节点的值相同,左子树相同,右子树相同
- 符合 “分 解 合” 特性
3.3 解题步骤
- 分:获取两个树的左子树和右子树
- 解:递归地判断两个树的左子树是否相同,右子树是否相同
- 合:将上述结果合并,如果根节点的值也相等,树就相同
function isSameTree(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
}
3.4 时间复杂度&空间复杂度
- 时间复杂度:O(n)
- 空间复杂度:O(n)
4. 对称二叉树(101)
4.1 题目描述
- 给你一个二叉树的根节点 root , 检查它是否轴对称
4.2 解题思路
输入:root = [1,2,2,3,4,4,3]
输出:true
- 转化为:左右子树是否镜像
- 分解为:树1的左子树和树2的右子树是否镜像;树1的右子树和树2的左子树是否镜像
- 符合 “分 解 合” 特性
4.3 解题步骤
- 分:获取两个树的左子树和右子树
- 解:递归地判断树1的左子树和树2的右子树是否镜像;树1的右子树和树2的左子树是否镜像
- 合:如果上述成立且根节点值相同,两个树就是镜像
function isSymmetric(root) {
if(!root) return true
const isMirror = (l, r) => {
if(l && r && l.val === r.val &&
isMirror(l.left, r.right) &&
isMirror(l.right, r.left)
) {
return true
}
return false
}
isMirror(root.left, root.right)
}
4.4 时间复杂度&空间复杂度
- 时间复杂度:O(n)
- 空间复杂度:O(n)
三、总计 -- 技术要点
- 分而治之是 算法设计 中的一种方法
- 它将一个问题 分 成多个和原问题相似的小问题, 递归解决 小问题,再将结果 合 并以解决原来的问题
- 应用场景:归并排序、快速排序、二分搜索、翻转二叉树……
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)