分治,字面上的解释是“分而治之”,
就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……
直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
在计算机科学中,分治法就是运用分治思想的一种很重要的算法。
分治法是很多高效算法的基础,如排序算法(快速排序,归并排序)等等。
例1:二分查找
已知有序的序列,比如:2,3,3,5,9,9,9,12,12,13,15,22,22,22,22,25,25,23,91,95
有整数x,比如: x=23
要求找到一个刚好比x稍微大一点的元素位置
当数组较大的时候,需要二分查找加快速度。
解:
public class Main {
// 含有begin, 不含end
static int f(int[] a, int begin, int end, int x) {
if (end - begin == 1) {// =1时代表只剩一个元素
if (a[begin] > x)
return begin;
return end;
}
int k = (begin + end) / 2;// k在begin和end的中心点
if (x >= a[k])// x大于a[k]时,就证明要找的那个刚大于x的数在中心点右边
return f(a, k, end, x);// 原中心点成为begin
return f(a, begin, k, x);// 否则就在中心点左边,原中心点成为end
}
// 求x应该插入的位置
// return 刚好比x稍微大点的那个数的位置
static int f(int[] a, int x) {
// 当到达数组最后一个数时,发现还没找到,就不存在比x大的数
if (x >= a[a.length - 1])
return -1;
return f(a, 0, a.length, x);// begin和end一开始是数组的开头和结尾
}
public static void main(String[] args) {
int[] a = { 1, 5, 11, 24, 25, 32, 32, 33, 49, 66, 68, 69, 70, 75, 88, 102, 114, 119, 120, 135, 146, 221, 294,
300, 302, 305, 333 };
System.out.println(f(a, 32));// 查找稍大于32的数的下标,是7
}
}
例2:最大序列和
数组中整数有正有负
求一连续子段,使得和最大化
例如:2,4,-7,5,2,-1,2,-4,3
最大连续段:
5,2,-1,2
其最大和为8
解:
public class Main {
static int fun(int[] a, int begin, int end) {
if (end - begin == 1) {// 只有一个元素时
if (a[begin] > 0)
return a[begin];
return 0;// 如果那个元素为负数,则返回0
}
int k = (begin + end) / 2;// 中点
int t1 = fun(a, begin, k);// 中点到左端点的最大连续部分和
int t2 = fun(a, k, end);// 中点到右端点的最大连续部分和
// 经过中点的最大连续部分和
int sum = 0;
// 左部分
int t3_a = 0;
for (int i = k - 1; i >= begin; i--) {// 不包括k
sum += a[i];
if (sum > t3_a)
t3_a = sum;
}
sum = 0;// 重置
// 右部分
int t3_b = 0;
for (int i = k; i < end; i++) {
sum += a[i];
if (sum > t3_b)
t3_b = sum;
}
int t3 = t3_a + t3_b;
// 找出三者中最大那个,就是整个序列的最大连续部分和
int max = 0;
if (t1 > max)
max = t1;
if (t2 > max)
max = t2;
if (t3 > max)
max = t3;
return max;
}
static int work(int[] a) {
return fun(a, 0, a.length);
}
public static void main(String[] args) {
// 随便创建一个序列作为尝试,下面这个会输出:8
System.out.println(work(new int[] { 2, 4, -7, 5, 2, -1, 2, -4, 3 }));
}
}