Java / 分治算法

分治算法

1. 前言

本节内容是分治算法系列之一:分治算法的介绍,主要介绍了分治算法的定义及基本思想和实现策略,然后我们介绍了一下分治算法的实现步骤,最后说明了一下哪些问题适合应用分治算法求解分析。

2. 什么是分治?

在计算机科学与技术领域中,分治法(Divide and Conquer) 是一种常见的算法思想。

分治法的理解其实很简单,直接按照字面的意思理解就可以:“分而治之”。(divide)是将一个大的问题分解成一些小的问题分别求解, (conquer)则是将分解的问题答案合并在一起,整个过程则是分而治之。这个算法技巧是很多算法的基础,我们之前学过的快速排序,其中就有分治思想的应用。

简单来说,分治法就是将一个复杂的大问题分解成两个或者更多相同或者相似的子问题,再把子问题继续拆分成更小的子问题,直到子问题可以直接求解,然后原问题的解就是子问题的解的合并。

3. 分治法的基本思想及实现策略

主要思想:分治法将一个规模较大的问题,拆分成一些规模较小的相同问题,小问题各个求解,再合并成大问题的解。这个是分值算法的主要思想。

实现策略:分治算法对于一个规模较大 的问题(假设其规模为 n ),如果当规模 n 的问题很容易解决则直接解决;否则就将这个规模为 n 的大问题拆分为几个规模为 k (规模 k 小于规模 n ) 的子问题,这些子问题与原问题的形式相同,则可以递归地求解这些子问题,然后将各个子问题的解合并得到原先的大问题的解。

分治法是否可行主要就在于这个大问题是否可以拆分为相同形式的小问题,然后这些小问题可解并将小问题的解合并成为原问题的解。因此,分治法所能够解决的问题一般都会具有如下几个特征:

  1. 待求解问题可以拆分成相同形式的规模较小的问题;
  2. 待求解问题在规模缩小到一定程度之后就可以很容易求解
  3. 利用待求解问题拆分出的子问题的解可以合并为待求解问题的解;
  4. 待求解问题拆分出来的子问题是相互独立的,子问题之间不会包含相同的子问题。

4. 分治法的基本步骤

在明确分治法的定义及其主要思想和实现策略之后,我们需要掌握实现分治法的主要步骤:

  1. 步骤 1:

    将待求解问题拆分成若干个规模较小、相互独立的子问题,子问题的形式与待求解问题相同;

  2. 步骤 2:

    若干个子问题如果很容易求解则直接求解,如果不容易求解则递归的解各个子问题;

  3. 步骤 3:

    将各个子问题分别求解的结果合并成待求解问题的解。

基于以上的三个步骤,分治算法一般可以总结成下面的伪代码:

divideAndConquer(big_problem){
   if (canSolve(big_problem)){ //问题可以直接求解则直接求解返回
       solve(big_problem); //求解
       return; 
   }else {
       small_problem_A = divide(big_problem); //不能直接求解的问题拆分
       small_problem_B = divide(big_problem); //不能直接求解的问题拆分
       divideAndConquer(small_problem_A); //递归求解子问题
       divideAndConquer(small_problem_B); //递归求解子问题
       return merge(); //合并子问题的解
   }
}

5. 分治法的应用场景

在日常的生活学习中,分治算法一般可以用来解决很多实际问题。下面,我们来看两个分治算法求解问题的实例。

实例 1: 二分搜索

二分搜索是一种很常见的搜索策略,他的核心思想也是利用到分治算法。二分搜索是在一个有序的数组中,通过均匀二分,每次折半查找,就是应用到分治法中将大问题缩减到小问题,这个小问题的最后结果就是刚好找到需要查找搜索的元素,这样小问题得出解,这个解也是最开始的待搜索的元素。

实例 2: 全排列问题

现实生活中,我们经常会遇见这样的场景,比如有 3 个小朋友排成一列,问你一共有多少种可以排列的情况,这个问题类似于数学中的全排列问题,这个时候利用分治算法也可以很好地进行求解。

先依次从三个小朋友中选择一位排在队列最前面,剩下的两个小朋友可以进行全排列,也可以继续拆分,二者选择其一进行即可,这个时候其实很清楚,他们只有两种排列情况了,然后跟前面的小朋友排列组合在一起。

比如我们用 A,B,C 代表三个小朋友,他们的排列情况演示如下:

//初始需要排列的元素
[A,B,C]   

//依次从三个小朋友中选择一位排在队列最前面,剩下的两个小朋友全排列
A[B,C]; B[A,C]; C[A,B] 

//剩下的两个小朋友排列情况只有两种,与之前的合并在一起    
ABC,ACB,BAC,BCA,CAB,CBA 

在现实工作和学习中会经常遇见,这是一种解决问题的思路与方法,将待求解的大问题拆分成小问题,然后解决小问题,再将小问题的解合并得出整个问题的解。

6. 小结

本节主要介绍了分治算法的定义及基本思想,在学完本节课程之后,需要明白分治算法的基础思想和实现逻辑是什么样的,如何自己去设计一个分治算法,什么样的问题适合用分治算法求解,以及在我们日常中常见的分治算法求解的问题。