快速排序
本质是分治,从某种程度上有点像动态规划,都是将问题转换为子问题
核心思路:将某一个序列重新排列,使得存在某个位置,其左小于等于自己,其右大于等于自己,然后对左右两段重复上述操作
看一下Deepseek给出的动态规划与分治的关系:
动态规划与分治算法是算法设计中一对关系密切、却又有着本质区别的思想。它们都体现了"化大为小"的智慧,但处理子问题的方式截然不同。
下面从共同点和区别两个维度来梳理它们的关系。
一、两者的共同点
都采用问题分解策略:两者都将一个复杂的大问题拆分成若干个规模更小的子问题,通过求解子问题再合并出原问题的解。都要求最优子结构性质:原问题的最优解必须包含子问题的最优解,这样才能保证通过子问题的最优解可以推导出全局最优解。
都存在递推关系:分治通过递归式层层分解,动态规划通过状态转移方程递推求解,本质上都是在描述问题之间的递推规律。
二、两者的核心区别
1. 子问题是否独立(最本质的差异)
表格
算法 子问题关系
分治算法 子问题相互独立,彼此之间没有重叠
动态规划 子问题相互重叠,不同的子问题可能包含公共的子子问题
分治的子问题各自为政,互不干扰。比如归并排序中,对左半数组的排序和对右半数组的排序是完全独立的两个操作,左半边的排序结果不会影响右半边。动态规划的子问题则是一环套一环的,同一子问题可能被多次重复计算。比如计算斐波那契数列时,f(5)需要用到f(4)和f(3),而f(4)又需要用到f(3)和f(2),f(3)被重复计算了。如果放任这种重复,计算量会呈指数级增长。
2. 是否保存子问题的解
分治法:不刻意保存子问题的解,每次递归都重新计算,因为子问题本身就是独立不重叠的,没必要存储。
动态规划:必须用表格(数组、哈希表等)将已求解过的子问题结果保存下来,再遇到时直接查表取出,从而避免大量重复计算。这正是动态规划从指数复杂度降至多项式复杂度的关键。
3. 求解方向
分治法:通常是自顶向下的递归结构。先分解到底,再逐层合并返回。
动态规划:通常采用自底向上的迭代方式,从小问题推到大问题;也可以用带备忘录的自顶向下递归(记忆化搜索)。
三、一个生动的类比
用考学的例子来理解这个区别:分治思想——高考:大目标是"高考取得好成绩",可以拆分成语文、数学、英语等各个科目来分别攻克。语文学得好不好,并不影响数学的学习成果,这些子问题是互相独立的,逐一解决后合并起来就能达成总目标。
动态规划——考博士:目标是"考上博士",需要拆分成上高中→上大学→考研→考博这一系列阶段。不上高中就不能上大学,不上大学就不能考研,每一个阶段的结果都会"传递"给下一阶段,子问题是有衔接、有状态转移的。而且每个阶段的"最优路径"依赖于上一阶段的成果,体现的就是状态递推关系。
四、从典型案例看差异
表格
维度 分治算法典型:归并排序 动态规划典型:斐波那契数列 / 打家劫舍
分解方式 将数组对半拆成两个子数组,各自排序 将n间房子的最优解拆成与n-1间、n-2间相关
子问题关系 左右子数组的排序完全独立 f(3)同时被f(4)和f(5)依赖,存在重叠
解的合并 用双指针将两个有序子数组合并成一个有序数组 通过状态转移方程(如 dp[i]=max(dp[i-1], dp[i-2]+nums[i]))递推
若不做记忆化 不影响结果,因为子问题不重复 会导致指数级重复计算,效率极低
五、总结
分治算法和动态规划的本质关系可以概括为:两者都是通过组合子问题的解来求解原问题。区别在于,分治法的子问题是独立不重叠的,直接递归求解即可;动态规划的子问题是重叠的,必须通过保存子问题解的方式来避免重复计算。
在实际应用中,如果把动态规划的题目用纯分治的方式去做,往往会因为反复求解相同子问题而导致指数级别的时间复杂度,这也是为什么需要"动规"这一专门方法来应对这类问题。
如果你有具体的题目想对比分析,或者想进一步了解动态规划的状态转移方程怎么设计,随时可以继续聊。
void quick_sort(int q[],int l,int r){
if (l>=r) return;
int x=q[l+r>>1],i=l-1,j=r+1;
while (i<j){
do{
i++;
}while (q[i]<x);//First
do{
j--;
}while (q[j]>x);
if (i<j){
swap(q[i],q[j]);
}
}
quick_sort(q,l,j);//Second
quick_sort(q,j+1,r);
}
快排写法千千万,此般写法不寻常
//First 为什么不取等?如果取等,带数据【5换行1 2 5 2 1】就爆栈了
//Second 能不能把j和j+1换成i-1和i?不可以,带数据【2换行1 2】爆栈
这个Second让我想到了二分,于是我明白了每当我MB时代【2换行1 2】数据试一下
变式
如果我只关心求第k小的数,我可以剪枝【 x+1>=k ? quick_sort(q,l,j) : quick_sort(q,j+1,r)】

171

被折叠的 条评论
为什么被折叠?



