一、分治法概述
1、基本概念
分治法(Divide and Conquer,也称为“分而治之法”)是一种很重要的算法,我们可以应用分治法来逐一拆解复杂的问题,核心思想是将一个难以直接解决的大问题按照相同的概念分割成两个或更多的子问题,以便各个击破,即“分而治之”。
其实任何一个可以用程序求解的问题所需的计算时间都与其规模与复杂度有关,问题的规模越小,越容易直接求解,因此可以使子问题的规模不断缩小,直到这些子问题简单到可以解决,最后将各个子问题的解合并,得到原问题的答案。
分治法依据以下步骤来解决问题。
1、划分:这涉及将问题划分为更小的子问题。
2、解决:通过递归调用解决子问题,直到解决。
3、合并:合并子问题得到整个问题的最终解。
2、简单示例
分而治之的一个经典例子是下面展示的合并排序。在合并排序中,我们将数组分成两半,对两半进行递归排序,然后将排序后的两半合并。
3、常见分治法的算法
1、快速排序是一种排序算法。该算法选择一个枢轴元素并重新排列数组元素,以便所有小于所选择的枢轴元素的元素都移动到枢轴的左侧,所有更大的元素都移动到右侧。最后,该算法递归地对枢轴元素左右的子数组进行排序。
2、归并排序也是一种排序算法。该算法将数组分成两半,对它们进行递归排序,最后将排序后的两半合并。
3、最近的点对 问题是在 xy 平面的一组点中找到最近的点对。通过计算每对点的距离并比较距离以找到最小值,可以在 O(n^2) 时间内解决该问题。分治算法在 O(N log N) 时间内解决了这个问题。
4、Strassen 算法是一种将两个矩阵相乘的有效算法。将两个矩阵相乘的简单方法需要 3 个嵌套循环并且是 O(n^3)。Strassen 算法在 O(n^2.8974) 时间内将两个矩阵相乘。
5、Cooley-Tukey 快速傅里叶变换 (FFT) 算法是最常见的 FFT 算法。它是一种分治算法,在 O(N log N) 时间内工作。
6、用于快速乘法的 Karatsuba 算法最多将两个n位数字
4、分治和递归
递归是一种很特殊的算法,分治法和递归法很像一对孪生兄弟,都是将一个复杂的算法问题进行分解,让规模越来越小,最终使子问题容易求解。简单来说,对程序设计人员而言,“函数”(或称为子程序)不单纯是能够被其他函数调用(或引用)的程序单元,在某些程序设计语言中还提供了自己调用自己的功能,这种调用的功能就是所谓的“递归”。
从程序设计语言的角度,谈到递归的正式定义,我们可以这样描述:假如一个函数或子程序是由自身所定义或调用的,就称为递归。递归至少要定义两个条件:①包括一个可以反复执行的递归过程,②一个跳出递归过程的出口。
二、分治法与动态规划的区别
分治法和动态规划都将给定问题划分为子问题并解决子问题。如何为给定的问题选择那种方法?当相同的子问题没有被多次解决时,应该使用分而治之。否则应使用动态编程或记忆。
例如,快速排序是一种分治算法,我们永远不会再次解决相同的子问题。另为了计算第 n 个斐波那契数,应该首选动态规划。