算法总结之 在两个长度相等的排序数组中找到上中位数
题目描述: arr1 和 arr2 长度都为N 求两个数组中所有数的上中位数
要求 时间复杂度 O(logN) 额外空间复杂度O(1)
这道题目的方法比较好玩:
这两个数组如下表示:
arr1[start1....end1] arr2[start2...end2]
如果start1==start2 那么也有start2==end2 此时元素总个数是2个,上中位数为最小的那个
如果start1!=start2 令mid1={start1+end1}/2 mid1={start2+end2}/2
进而分情况
情况一、 如果arr1[mid1] == arr2[mid2]
如果两个数组长度为奇数或者偶数,那么arr1[mid1] == arr2[mid2]=上中位数
情况二、如果arr1[mid1] >arr2[mid2]
如果长度为奇数、(假设为5)arr1的第三个数>arr2的第三个数 此时上中位数只能是从arr1的{1,2,3}和arr2的{3,4,5}的共同的上中位数找
如果长度为偶数,(假设为4)arr1的第二个数>arr2的第二个数 此时上中位数只能是从arr1的{1,2}和arr2的{3,4}的共同的上中位数找
如果arr1[mid1] <arr2[mid2]情况完全一致 请读者自行推理
代码实现是这样:
特别类似于二分查找 哈哈 也是找mid 然后通过min去比较
其实两个数组长度是一致的 某种程度上说是当前数组的影子 或者 映射吧 都是有关联的 所以重点操作一个数组 然后通过某种关系去映射另外一个数组就OK了
比较两个数组mid的值 决定两个数组 后面遍历的走向
废话不多说,上代码:
package TT; public class Test12 { public static int getUpMedian(int[] arr1 , int[] arr2){ if(arr1==null || arr2==null || arr1.length != arr2.length){ throw new RuntimeException("hi,babay.are you ok?"); } int start1 =0; int end1 = arr1.length-1; int start2=0; int end2 = arr2.length-1; int mid1 =0; int mid2 =0; int offset = 0; while(start1 < end1){ mid1 = (start1+end1)/2; mid2 = (start2+end2)/2; //元素个数如果是奇数为0 偶数为1 offset = ((end1 - start1+1)&1)^1; if(arr1[mid1] > arr2[mid2]){ end1 = mid1; start2=mid2+offset; }else if(arr1[mid1]<arr2[mid2]){ start1 = mid1 + offset; end2 = mid2; }else { return arr1[mid1]; } } return Math.min(arr1[start1], arr2[start2]); } public static void main(String[] args){ int[] a1 = new int[4]; int[] a2 = new int[4]; a1[0]=0; a1[1]=1; a1[2]=2; a1[3]=3; a2[0]=4; a2[1]=5; a2[2]=5; a2[3]=6; int c = getUpMedian(a1,a2); System.out.println(c); } }
结果:
手写实现很多思路,我觉得这样写是最清晰明了的
public class Test4 { public static int getMidValue(int[] arr1, int[] arr2) { // 参数验证 if (arr1 == null || arr2 == null || arr1.length != arr2.length) { throw new RuntimeException("请检查参数"); } // 执行业务逻辑 (左右指针) int start1 = 0; int end1 = arr1.length - 1; int start2 = 0; int end2 = arr2.length - 1; while (start1 < end1) { int mid1 = (end1 - start1) / 2; int mid2 = (end2 - start2) / 2; // 移动的开关 (元素个数奇数偶数判断取决于 移动与否) int offset = (end1-start1+1)%2 == 0 ? 1 : 0; //时刻判断 if (arr1[mid1] > arr2[mid2]) { end1 = mid1; start2 = mid2 + offset; } else if (arr1[mid1] < arr2[mid2]) { end2 = mid2; start1 = mid1 + offset; } // 如果相等的话就直接返回了 return Math.min(arr1[start1], arr2[start1]); } return Math.min(arr1[start1], arr2[start1]); } public static void main(String[] args) { int[] arr1 = { 1, 3, 5, 7 }; int[] arr2 = { 2, 4, 6, 8 }; int midValue = getMidValue(arr1, arr2); System.out.println(midValue); } }