随笔 - 77  文章 - 1 评论 - 10 阅读 - 68913
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

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

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代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//这里未进行开方<br><br>   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   Judy518  阅读(540)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示