分治法
1) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
2) 利用该问题分解出的子问题的解可以合并为该问题的解;
3) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
应用到
归并排序
每次排序的时候左右两边是已经排好顺序的两块数组,不用再组内排序,而是对于两个数组之间无序情况使用外排序将不同的数组块进行排序,这样相对于暴力破解节省的是不必要的比较时间复杂度。(组内有序,组间无序)
public class MergeSort {
public static void mergeSort(int[] arr) {
if(arr == null || arr.length < 2) {
return;
}
mergeSort(arr, 0, arr.length - 1);
}
public static void mergeSort(int[] arr, int left, int right) {
if(left == right) {
return;
}
int mid = left + ((right - left)>>1);
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
public static void merge(int[] arr, int left, int mid, int right) {
int[] help = new int[right - left + 1]; //排序的辅助空间
int i = 0;
int p1 = left;
int p2 = mid + 1;
while(p1 <= mid && p2 <= right) {
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while(p1 <= mid) { //左侧数组有序,不用排序,直接合并到数组help中
help[i++] = arr[p1++];
}
while(p2 <= right) {
help[i++] = arr[p2++];
}
//辅助空间排好序后,覆盖原数组
for(int j = 0; j < help.length; j++) {
arr[left + j] = help[j];
}
}
public static void main(String[] args) {
int[] arr = {4, 3, 2, 1};
mergeSort(arr);
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
逆序对(利用归并排序)
利用子问题解的合并,进行问题的求解
re += arr[p2] < arr[p1] ? ((mid - p1 + 1)) : 0;
当两块数组进行合并的时候,右侧的数组将第一个元素小于左侧的一个元素时候,则意味着小于左侧的所有元素,这样就得到了右侧第一个元素的逆序对;右侧的数组指针移动,指向第二个元素,和左侧的指针元素进行比较,由于左侧的数组是有序的,小于第一值,则小于后面的值;依次类推。组间有序,组外无序。利用组间有序节省计算量。
但是,值得注意的是,将两块数组合并之后,整体还是有序的;为下一个子任务提供便利。
package baisc_class_01;
public class InversePairs {
public static int inversePair(int[] arr) {
if(arr == null || arr.length < 2) {
return 0;
}
return mergeSort(arr, 0, arr.length - 1);
}
public static int mergeSort(int[] arr, int left, int right) {
if(left == right) {
return 0;
}
int mid = left + ((right - left) >> 1);
int leftSum = mergeSort(arr, left, mid);
int rightSum = mergeSort(arr, mid + 1, right);
int sum = leftSum + rightSum + merge(arr, left, mid, right);
return sum;
}
public static int merge(int[] arr, int left, int mid, int right) {
int[] help = new int[right - left + 1];
int p1 = left;
int p2 = mid + 1;
int re = 0;
int i = 0;
while(p1 <= mid && p2 <= right) {
re += arr[p2] < arr[p1] ? ((mid - p1 + 1)) : 0;//核心 利用子问题解的的合并
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while(p1 <= mid) {
help[i++] = arr[p1++];
}
while(p2 <= right) {
help[i++] = arr[p2++];
}
for(int j = 0; j < help.length; j++) {
arr[left + j] = help[j];
}
return re;
}
public static void main(String[] args) {
int[] arr = {4,3,2,1};
System.out.println(inversePair(arr));
for(int i = 0; i < arr.length; i++)
System.out.println(arr[i]);
}
}