分治算法详解

来源:互联网 发布:搜狐域名邮箱注册 编辑:程序博客网 时间:2024/06/05 15:04

一、分治算法的基本思想
  当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出。对于这类问题,我们往往先把它分解成几个子问题,找到求出这几个子问题的解法后,再找到合适的方法,把它们组合成求整个问题的解法。如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。这就是分治策略的基本思想。
  所以分治算法中的“分”具体是值用递归解决规模较小的问题 ,”治“具体是指从子问题的解构建原问题的解。具体来讲就是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。即一种分目标完成程序算法,简单问题可用二分法完成。

二、分治算法解决的问题的特征
  分治法所能解决的问题一般具有以下几个特征:
  (1)该问题的规模缩小到一定的程度就可以容易地解决;
  (2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;
  (3)利用该问题分解出的子问题的解可以合并为该问题的解;
  (4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。
   说明:第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;第二条特征是应用分治法的前提它也是大多数问题可以满足的,此特征反映了递归思想的应用;第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法。第四条特征涉及到分治法的效率,如果各子问题是不独立的则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。

三、分治算法的基本步骤
  分治法解题的一般步骤:
  (1)分解,将要解决的问题划分成若干规模较小的同类问题;
  (2)求解,当子问题划分得足够小时,用较简单的方法解决;
  (3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。

四、leetcode上关于分治算法的实例
4.1 Pow(x, n)
(1)题意
  求解x的n次方,要求时间复杂度为O(logn)。
(2)python代码

class Solution:    def myPow(self, x, n):        if not n:            return 1        if n < 0:            return 1 / self.myPow(x, -n)        if n % 2:            return x * self.myPow(x, n-1)        return self.myPow(x*x, n/2)

4.2 Sqrt(x)
(1)题目
  求x的开平方根,要求时间复杂度为o(logn)。
(2)python代码

class Solution(object):    def mySqrt(self, x):        """        :type x: int        :rtype: int        """        l,r = 0,x        while l<=r:            mid=(r+l)//2            if mid*mid<= x <(mid+1)*(mid+1):                return mid            elif x < mid*mid:                r=mid            else:                l=mid+1

五、使用分治算法求解的一些经典问题
  (1)二分查找;
  (2)大整数乘法;
  (3)Strassen矩阵乘法;
  (4)棋盘覆盖;
  (5)合并排序;
  (6)快速排序;
  (7)线性时间选择;
  (8)最接近点对问题;
  (9)循环赛日程表;
  (10)汉诺塔。