分治算法一般用递归来实现,分治算法是一种处理问题的思想,递归是一种编程技巧,在分治算法的递归实现中,每一层递归都会涉及这三个操作:
1、分解:将原问题分解成一系列子问题;
2、解决:递归求解各个子问题,若子问题足够小,则直接求解;
3、合并:将子问题的结果合并成原问题。
满足下面几个条件,则可以使用分治算法:
1、原问题与分解成的小问题具有相同的模式;
2、原问题分解成的子问题可以独立求解,子问题之间没有相关性;
3、具有分解终止条件,也就是说,当问题足够小时,可以直接求解;
4、可以将子问题合并成原问题,而且这个合并操作的复杂度不能太高,否则起不到减小算法总体复杂度的效果。
归并排序就是用了分治算法思想,接下来用分治算法求解一组数组的逆序对。逆序对:一组数据中,前面的数比后面大,那么这两个数就是一对逆序对,比如[4,2,3,5],4比2大,4比3大,所以逆序对为2,有序对=总对数-逆序对,总对数为n(n-1)/2。代码如下:
public int num = 0;
public int count(int[] a) {
mergeSortCounting(a, 0, a.length-1);
return num;
}
private void mergeSortCounting(int[] a, int start, int end) {
if(start >= end) {
return;
}
int middle = (start+end)/2;
mergeSortCounting(a, start, middle);
mergeSortCounting(a, middle+1, end);
merge(a, start, middle, end);
}
private void merge(int[] a, int start, int middle, int end) {
int left = start, right = middle+1;
int[] temp = new int[end-start+1];
int index = 0;
while(left <= middle && right <= end) {
if(a[left] <= a[right]) {
temp[index++] = a[left++];
} else {
num += middle-left+1;
temp[index++] = a[right++];
}
}
while(left <= middle) {
temp[index++] = a[left++];
}
while(right <= end) {
temp[index++] = a[right++];
}
for(int i = 0; i < end-start+1; i++) {
a[start+i] = temp[i];
}
}
leetcode53题代码
/**
* leetcode53
* 给定一个整数数组(有正数有负数),找出总和最大的连续数列,并返回总和。
*
* 示例:
* 输入: [-2,1,-3,4,-1,2,1,-5,4]
* 输出: 6
* 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
*
* @param nums
* @return
*/
public int maxSubArray(int[] nums) {
int maxNum = nums[0];
for(int i = 0; i < nums.length; i++) {
int currentMax = nums[i];
maxNum = nums[i] >= maxNum ? nums[i] : maxNum;
for(int j = i + 1; j < nums.length; j++) {
currentMax = nums[j] + currentMax;
maxNum = currentMax >= maxNum ? currentMax : maxNum;
}
}
return maxNum;
}
/**
* 分治算法
* @param nums
* @return
*/
public int maxSubArray01(int[] nums) {
return dacMaxSubArray(nums, 0, nums.length-1);
}
private int dacMaxSubArray(int[] nums, int left, int right) {
if(left == right) {
return nums[left];
}
int middle = (left+right)/2;
int leftMax = dacMaxSubArray(nums, left, middle);
int rightMax = dacMaxSubArray(nums, middle+1, right);
int middleToLeftMax = Integer.MIN_VALUE;
int middleToLeftCurrentMax = 0;
for(int i = middle; i >= left; i--) {
middleToLeftCurrentMax += nums[i];
middleToLeftMax = Math.max(middleToLeftCurrentMax, middleToLeftMax);
}
int middleToRightMax = Integer.MIN_VALUE;
int middleToRightCurrentMax = 0;
for(int j = middle+1; j <= right; j++) {
middleToRightCurrentMax += nums[j];
middleToRightMax = Math.max(middleToRightCurrentMax, middleToRightMax);
}
int middleMax = middleToLeftMax + middleToRightMax;
return Math.max(middleMax, Math.max(leftMax, rightMax));
}
/**
* 动态规划
* @param nums
* @return
*/
public int maxSubArray02(int[] nums) {
int max = nums[0];
int sum = nums[0];
for(int i = 1; i < nums.length; i++) {
if(sum < 0) {
sum = nums[i];
} else {
sum += nums[i];
}
max = Math.max(sum, max);
}
return max;
}