关于一些分治问题的算法题目笔记
1.两个有序数组求合并数组的中位数要求复杂度在O(log (m+n))
示例1:
输入:
[100, 300],[200]
返回值:
200.00000
说明:
合并体重 = [100,200,300] ,中位数 200
描述:典型的分治问题,求中位数可以视为求第(n+m)/2个数,每次对比k/2的大小,每次可以直接排除k/2个数。
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param weightsA int整型一维数组
* @param weightsB int整型一维数组
* @return double浮点型
*/
public double findMedianSortedArrays (int[] weightsA, int[] weightsB) {
// write code here
int n=weightsA.length;
int m=weightsB.length;
return (getKth(weightsA,0,n-1,weightsB,0,m-1,(m+n+1)/2)+getKth(weightsA,0,n-1,weightsB,0,m-1,(m+n)/2+1))*0.5;
}
public int getKth(int[] nums1,int l1,int r1,int[] nums2,int l2,int r2,int k){
//得到两个数组的剩余长度
int len1=r1-l1+1;
int len2=r2-l2+1;
//让第一个数组为长度较小的数组
if(len1>len2){
getKth(nums2,l2,r2,nums1,l1,l2,k);
}
//当一个数组的值已经完全排除了
//则要找的数就是剩余另一个数组的k+1
if(len1==0){
return nums2[l2+k-1];
}
if(k==1){
return Math.min(nums1[l1],nums2[l2]);
}
//防止k/2的值大于剩余长度
int i=l1+Math.min(k/2,len1)-1;
int j=l2+k/2-1;
//此时舍弃第一个数组的左半边,k此时也要减去舍弃的数量
if(nums1[i]<=nums2[j]){
return getKth(nums1,i+1,r1,nums2,l2,r2,k-(i-l1+1));
}else{
//否则舍弃第二个数组的左半边
return getKth(nums1,l1,r1,nums2,j+1,r2,k-(j-l2+1));
}
}
}
2.三个有序数组求合并数组的中位数要求复杂度在O(log (m+n+p))
示例1:
输入:
[1,3],[2],[4,5]
返回值:
3.00000
说明:
合并数组 = [1,2,3,4,5] ,中位数 3
描述:上一题的升级版,可以以同样的思路,每次排除最小值中数组的数。
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param herd1 int整型一维数组
* @param herd2 int整型一维数组
* @param herd3 int整型一维数组
* @return double浮点型
*/
public double findMedianSortedArray (int[] herd1, int[] herd2, int[] herd3) {
// write code here
int n1=herd1.length,n2=herd2.length,n3=herd3.length;
int length=n1+n2+n3;
int left = (length + 1) / 2;
int right = (length + 2) / 2;
return (getKth_3(herd1, 0, n1 - 1, herd2, 0, n2 - 1, herd3, 0, n3 - 1, left) + getKth_3(herd1, 0, n1 - 1, herd2, 0, n2 - 1, herd3, 0, n3 - 1, right)) * 0.5;
}
public int getKth_3(int[]herd1,int l1,int r1,int[]herd2,int l2,int r2,int[]herd3,int l3,int r3,int k){
int len1=r1-l1+1;
int len2=r2-l2+1;
int len3=r3-l3+1;
//让数组的长度从小到大排序
if(len2<len1&&len2<=len3){
return getKth_3(herd2,l2,r2,herd1,l1,r1,herd3,l3,r3,k);
}
if(len3<len1){
return getKth_3(herd3,l3,r3,herd2,l2,r2,herd1,l1,r1,k);
}
//如果其中一个数组的值为0那么就是两个数组的分治问题了
if(len1==0){
return getKth(herd2, l2, r2, herd3, l3, r3, k);
}
//如果中位数为1就取其中最小的一个
if (k == 1)
return Math.min(herd1[l1], Math.min(herd2[l2], herd3[l3]));
//和两个数组比较的思路一致,都是排除掉某个数组小的那部分每次排除k/2个
int u = l1 + Math.min(len1, k / 2) - 1;
int v = l2 + k / 2 - 1;
int w = l3 + k / 2 - 1;
int min_val = Math.min(herd1[u], Math.min(herd2[v], herd3[w]));
if (min_val == herd1[u])
return getKth_3(herd1, u + 1, r1, herd2, l2, r2, herd3, l3, r3, k - (u - l1 + 1));
else if (min_val == herd2[v])
return getKth_3(herd1, l1, r1, herd2, v + 1, r2, herd3, l3, r3, k - (v - l2 + 1));
else
return getKth_3(herd1, l1, r1, herd2, l2, r2, herd3, w + 1, r3, k - (w - l3 + 1));
}
int getKth(int[]herd1, int l1, int r1, int[]herd2, int l2, int r2, int k) {
int len1 = r1 - l1 + 1;
int len2 = r2 - l2 + 1;
if (len1 > len2)
return getKth(herd2, l2, r2, herd1, l1, r1, k);
if (len1 == 0)
return herd2[l2 + k - 1];
if (k == 1)
return Math.min(herd1[l1], herd2[l2]);
int i = l1 + Math.min(len1, k / 2) - 1;
int j = l2 + k / 2 - 1;
if (herd1[i] <= herd2[j])
return getKth(herd1, i + 1, r1, herd2, l2, r2, k - (i - l1 + 1));
else
return getKth(herd1, l1, r1, herd2, j + 1, r2, k - (j - l2 + 1));
}
}