分治算法也是一种重要的求解问题的思路,移用百科的定义,分治就是分而治之,就是将一个规模比较大的问题分解为几个规模较小的问题,这些规模较小的问题是相互独立的,但是它们与原问题性质相同,可以用相同的思路进行继续分解求解,最后将这些小规模的问题求解出的解合并起来作为原问题的解,故而分治算法的求解过程为:

a、分解:寻找将原问题分解为求解几个规模比较小的问题,这些小问题和原问题的性值是相同的

b、求解:将问题规模分解到一定程度,可以用简单的方法进行求解

c、合并:将这些子问题的解合并起来作为原问题的解返回给调用者

因为子问题和原问题是同构的,所以分治在一定程度上可以借助递归算法进行实现,递归算法更像是一种模板。以下是可以用分治算法思想的案例:

1、归并排序

归并排序是将问题先分解,然后进行排序,最后将小规模的排好序的子解合并为一个原问题的解,详见https://www.cnblogs.com/codeMedita/p/7412568.html

2、求解最大值

给定一个无序的数组arr,求解arr中的最大值,可有两种计算:

a 直接遍历求解

def maxVal(arr):

   int max=0;

   for val in arr:

     max=max>val?max:val;

   return max

b 分治方法求解

def dividAndConquer(arr,leftIndex,rightIndex):

  if(rightIndex==leftIndex+1 || rightIndex==leftIndex){

    return Math.max(arr[leftIndex],arr[rightIndex]);

  }

  int mid=(leftIndex+rightIndex)/2;

  int leftMax=dividAndConquer(arr,leftIndex,mid);

  int rightMax=dividAndConquer(arr,mid,rightIndex);

  return Math.max(leftMax,rightMax);

3、二分查找,给定一个从小到大有序的数组和一个值,求解改值在数组中的位置

def binarySearch(arr,leftIndex,rightIndex,val):

  if(leftIndex>rightIndex) return false;

  if(leftIndex==rightIndex):

    return arr[leftIndex]==val;

  int mid=(leftIndex+rightIndex)/2;

  if(arr[mid]==val) return true;

  if(arr[mid]>val){

    if(leftIndex==mid) return false;

    return binarySearch(arr,leftIndex,mid-1,val);

  }   

  return binarySearch(arr,mid+1,right,val);

4、输出一条线上距离最近的两个点之间的距离值,给定一个数组arr,其值是从小到大有序的,输出最近点的距离

def minDistance(arr,left,right):

  //同一个点返回极大值

  if(arr[left]==arr[right]) return Integer.MAX

      //相邻点的距离

  if(right==left+1) return arr[right]-arr[left];

  int mid=(left+right)/2;

  //中间点的临近点的距离,这里很重要!!!

  int midLeft=arr[mid]-arr[mid-1];

  int midRight=arr[mid+1]-arr[mid];

  //记录mid 附近两边的最小距离

  midLeft=midLeft>midRight?midRight:midLeft;

  int minLeft=minDistance(arr,left,mid);

  int minRight=minDistance(arr,mid+1,right);

  //记录mid 左侧和右侧的最小距离

  minLeft=minLeft>minRight?minRight:minLeft;

  //返回最小值

  return midLeft>minLeft?minLeft:midLeft;

5、输出平面上距离最近的两个点的距离,给定一个点集,求出这个点集中最近两点的距离,这里需要进行一些排序操作,计算描述:

a 按横坐标递增的形式对点集进行排序,相同的横坐标的点击再用纵坐标从小大大进行排序,然后切分点集,切分方法mid=(left+right)/2

b 计算(left,mid)中的点集最小距离minleft,计算(mid,right)中的点集最小距离minright,此时mid-left<=3,right-mid<=3,如果

mid-left>3,则继续对(left,mid)中的点集进行切分,(mid,right)同理

c 计算mid+min(midleft,minright)之间的点击,按照遍历的方式进行计算

伪代码描述:

def minDis(point,left,right):

  if(left+1==right):

    //distance为预先定义好的计算方法

    return distance(point[left],point[right]);

  if(left+2==right):

    dis1=distance(point[left],point[left+1]);

    dis2=distance(point[left+1],point[right]);

    dis3=distance(point[left],point[right]);

    return min(dis1,min(dis2,dis3));

  mid=(left+right)/2;

  minleft=minDis(point,left,mid);

  minright=minDis(point,mid+1,right);

  //计算出mid点左右两侧中距离较短的点对距离

  minMid=min(minleft,minright);

  //以minMid为长度找出距离mid不超过minMid的点

  for i=left to right:

    if(Math.abs(point[mid].x-point[i])<d  && mid!=i):

      tempMemory.add(point[i]);

  for i=0 to tempMemory.length:

    for j=i+1 to tempMomory.length:

      minMid=min(minMid,distance(point[i],point[j]);

  return minMid;

java代码示例:

   //这里未进行开方

  static int distance(List<Node> nodes,int left,int right){ Node leftNode=nodes.get(left),rightNode=nodes.get(right); int dis=(leftNode.x-rightNode.x)*(leftNode.x-rightNode.x)+ (leftNode.y-rightNode.y)*(leftNode.y-rightNode.y); return dis; } static int minDistance(List<Node> nodes,int left,int right){ if(right==left){ return Integer.MAX_VALUE; } if(right-1==left){ return distance(nodes,left,right); } if(right-2==left){ int m1=distance(nodes,left,left+1); int m2=distance(nodes,left+1,right); int m3=distance(nodes,left,right); return Math.min(m1,Math.min(m2,m3)); } int mid=(left+right)>>1; int leftmid=minDistance(nodes,left,mid); int rightmid=minDistance(nodes,mid+1,right); int minMid=Math.min(leftmid,rightmid); List<Node> temp=new ArrayList<>(); for(int i=left;i<right;i++){ if(Math.abs(nodes.get(i).x-nodes.get(mid).x)<minMid){ temp.add(nodes.get(i)); } } int dis=0; for(int i=0;i<temp.size();i++){ for(int j=i+1;j<temp.size();j++){ dis=distance(nodes,i,j); minMid=minMid>dis?dis:minMid; } } return minMid; }

分治算法重要步骤:

1、分解:大的问题进行互不相干的小问题

2、解决:将小到一定规模的问题用简单的方法计算出结果

3、合并:将小问题的解进行整合作为原始问题的解返给调用方

posted on 2021-09-20 21:04  Judy518  阅读(528)  评论(0编辑  收藏  举报