一、课程目标
- 分治思想
- 理解分治
- 核心步骤
- 简单案例
二、目标详解
1、分治思想
分治的基本思想是将一个规模为n的问题分解为多个规模较小的子问题,这些子问题与原问题相同又互相独立,每个子问题又递归分解,直到子问题求解完成,然后再将子问题的解合并得到原问题的解。
2、理解分治思想
分治思想的场景:当前问题估摸较大不好求解,而子问题在问题规模降到某一阀值时比较容易求解,因此通过递归分解子问题得到子问题的解,再将解逐层合并回来。
适合问题的主要特征:
- 规模较小(到一定阀值)时容易求解。
- 具有最优子结构性质(可分解为k个相同的子问题)
- 子问题的解可以合并回来
- 子问题相互独立(不含公共的子问题)
如果第3点不满足则不能使用分治,一般可用贪心或动态规划。
如果第4点不满足,则用分治的话就会产生很多重复运算,一般用动态规划会更好。
3、分治的核心步骤
分治的三个核心步骤:
- 分解子问题Divide
- 求解子问题Conquer
- 合并子问题的解Combine
由于需要持续分解,因此分治一般都采用递归的方式进行,问题的分解自上而下,解的合并自下而上。
伪代码如下:
void 分解与合并(问题P) {
if (问题规模 <= 规模阀值) return 求解(P);
分解成k个子问题P1...Pk;
for(i=1; i<=k; i++)
解yi = 分解与合并(Pi);
return 合并(y1, y2, ..., yk);
}
4、简单案例
问题:在一个单调序列里找一个数x,输出下标,没有找到就返回-1。
- 枚举法:循环比较
- 二分法:二分逼近
- 分治法怎么做呢?
分析
:
- 问题规模为n,当问题规模到1时,自然求解
- 每次将问题分成两个子问题,通过递归函数传入参数L和R的方式进行分解
- 此问题的解无需合并,直接返回即可
三、扩展理解
- 分治与递归
- 分治与二分
- 分治与动态规划
- 分治的经典应用很多,例如归并排序、快速排序等,更多的将在以后再提及。