分治算法总结

目录

  • 一、分治算法步骤
  • 二、基于分治策略的算法
    • 1、最大子数组问题
    • 2、矩阵乘法问题
  • 三、分治算法进阶
    • 1、大整数乘法
    • 2、最大值和最小值
    • 3、元素选取问题线性时间算法
    • 4、快速傅里叶变换

一、分治算法步骤

1、分解:将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小
2、解决:递归地求解出子问题。如果子问题的规模足够小,则停止递归,直接求解。
3、合并:将子问题的解组合成原问题的解

二、基于分治策略的算法

1、最大子数组问题

(1)问题定义:
在某一时间买进股票,之后的某个时间卖出,买进卖出都是在当天交易结束后进行。可以了解股票将来的价格。将第i天的价格变化定义为第i天和第i - 1天的价格差,得到一个数组A,问题转化为寻找A的和最大的非空连续子数组。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
13 -3 -25 20 -3 -16 -23 18 20 -7 12 -5 -22 15 -4 7

(2)求解方法:
使用分治技术求解最大子数组问题。找到数组中间位置mid,A[low…high]的最大连续子数组A[i…j]处于三种情况之一:
完全位于子数组A[low…mid]中
完全位于子数组A[mid+1…high]中
跨越中点
(3)求解代码:

public class FindMaximumSubarray {
   public static void main(String args[]) {
	   int A[] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
	   int size = A.length;
	   int result[] = new int[3];
	   result = findmaximum(A,0,size-1);
	   System.out.println(result[0]);
	   System.out.println(result[1]);
	   System.out.println(result[2]);
   }
   public static int[] findmaximum(int A[],int low,int high) {
	   int result[] = new int[3];
	   if(high==low) {
		   result[0] = low;
		   result[1] = high;
		   result[2] = A[high];
	   }
	   else {
		   int mid = (low + high)/2;
		   int resultleft[] = new int[3];
		   resultleft = findmaximum(A,low,mid);
		   int resultright[] = new int[3];
		   resultright = findmaximum(A,mid+1,high);
		   int resultcrossing[] = new int[3];
		   resultcrossing = findmaxcrossing(A,low,mid,high);
		   if(resultleft[2]>resultright[2]&&resultleft[2]==resultright[2]
				   &&resultleft[2]>resultcrossing[2]&&resultleft[2]==resultcrossing[2]) {
			   result = resultleft;
		   }
		   else if(resultright[2]>resultleft[2]&&resultright[2]==resultleft[2]
				   &&resultright[2]>resultcrossing[2]&&resultright[2]==resultcrossing[2])
			   result = resultright;
		   else 
			   result = resultcrossing;
	   }
	   return result;
   }
   public static int[] findmaxcrossing(int A[],int low,int mid,int high) {
	   int leftsum = Integer.MIN_VALUE;
	   int maxleft = mid;
	   int sum = 0;
	   for(int i = mid;i>=low;i--) {
		   sum = sum+A[i];
		   if(sum > leftsum) {
			   leftsum = sum;
		       maxleft = i;
		   }
	   }
	   int rightsum = Integer.MIN_VALUE;
	   int maxright = mid;
	   sum = 0;
	   for(int i =  mid+1;i<=high;i++) {
		   sum = sum + A[i];
		   if(sum > rightsum) {
			   rightsum = sum;
			   maxright = i;
		   }
	   }
	   int result[] = new int[3];
	   result[0] = maxleft;
	   result[1] = maxright;
	   result[2] = leftsum+rightsum;
	   return result;
   }
}

2、矩阵乘法问题

直接的矩阵乘法问题的时间复杂度是Ω(n^3)。
(1)简单的分治算法
在这里插入图片描述
将A,B,C矩阵都这样分解,然后分治方法求解,但是时间复杂度还是Ω(n^3)。
(2)Strassen方法:看书

三、分治算法进阶

1、大整数乘法

(1)问题定义:当整数在一个字以内时,直接进行乘运算,本问题计算的是两个很长的整数相乘。
(2)求解方法:
X = A | B,Y = C | D,XY = (A·2^(n/2)+B) · (C·2^(n/2)+D) = AC + (AD+BC) · 2^(n/2)+BD
并且AD+BC = (A-B)(C-D)+AC+BD,这样T(n) = 3T(n/2)+θ(n)

2、最大值和最小值

用递归树的解决方法将比较次数从2(n-2)+1降为3n/2-1

3、元素选取问题线性时间算法

(1)问题定义:从n个不同的数中选取第i大的数
(2)求解方法:
将数组分组,每组5个数,对每组里的这些数进行插入排序,找到每组中位数。
找到中位数的中位数MoM,并且对数组进行划分(xMoM),确定(MoM)的下标k。
i i=k,返回MoM;
i>k,递归的在后面找;

4、快速傅里叶变换

你可能感兴趣的:(算法设计与分析)