import java.util.*; /** * NC252 多数组中位数 * @author d3y1 */ public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param arr1 int整型一维数组 * @param arr2 int整型一维数组 * @return int整型 */ public int getUpMedian (int[] arr1, int[] arr2) { // return solution1(arr1, arr2); return solution2(arr1, arr2); // return solution3(arr1, arr2); // return solution4(arr1, arr2); } /** * 双指针 * @param arr1 * @param arr2 * @return */ private int solution1(int[] arr1, int[] arr2){ int n1 = arr1.length; int n2 = arr2.length; int k = (n1+n2+1)/2; int left1 = 0; int left2 = 0; while(true){ if(left1 == n1){ return arr2[left2+k-1]; } if(left2 == n2){ return arr1[left1+k-1]; } if(k == 1){ return Math.min(arr1[left1], arr2[left2]); } if(arr1[left1] <= arr2[left2]){ k--; left1++; }else{ k--; left2++; } } } /** * 二分 * * 思路: * 要找到第k(k>1)小的元素, 那么就取 mid1=arr1[k/2-1] 和 mid2=arr2[k/2-1] 进行比较 * arr1 中小于等于 mid1 的元素有 arr1[0 .. k/2-2] 共计 k/2-1 个 * arr2 中小于等于 mid2 的元素有 arr2[0 .. k/2-2] 共计 k/2-1 个 * 取 pivot = min(mid1, mid2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个 * 这样 pivot 本身最大也只能是第 k-1 小的元素 * 如果 pivot = mid1, 那么 arr1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除", 剩下的作为新的 arr1 数组 * 如果 pivot = mid2, 那么 arr2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除", 剩下的作为新的 arr2 数组 * 由于我们 "删除" 了一些元素(这些元素都比第 k 小的元素要小), 因此需要修改 k 的值, 减去删除的数的个数 * * @param arr1 * @param arr2 * @return */ private int solution2(int[] arr1, int[] arr2){ int n1 = arr1.length; int n2 = arr2.length; // 第k个数 (第k小的数) int k = (n1+n2+1)/2; int left1 = 0; int left2 = 0; int mid1,mid2; int half; while(true){ if(left1 == n1){ return arr2[left2+k-1]; } if(left2 == n2){ return arr1[left1+k-1]; } if(k == 1){ return Math.min(arr1[left1], arr2[left2]); } half = k/2; mid1 = Math.min(left1+half, n1)-1; mid2 = Math.min(left2+half, n2)-1; if(arr1[mid1] <= arr2[mid2]){ k -= (mid1-left1+1); left1 = mid1+1; }else{ k -= (mid2-left2+1); left2 = mid2+1; } } } /** * 二分: 划分数组 * * len(pre_part): 前一部分的元素个数 * len(post_part): 后一部分的元素个数 * * n1+n2为偶数时: * 确保 * (1). len(pre_part)=len(post_part) * (2). max(pre_part)≤min(post_part) * 则有 上中位数median=max(pre_part) * * 此时由(1)推得: * => i+j=n1−i+n2−j * => i+j=(n1+n2)/2 * * n1+n2为奇数时: * 确保 * (1). len(pre_part)=len(post_part)+1 * (2). max(pre_part)≤min(post_part) * 则有 上中位数median=max(pre_part) * * 此时由(1)推得: * => i+j=n1−i+n2−j+1 * => i+j=(n1+n2+1)/2 * * 可见: 无论(n1+n2)为奇为偶 * i+j = (n1+n2+1)/2 * => j= (n1+n2+1)/2 - i (0<=i<=n1 0<=j<=n2 n1<=n2) * * @param arr1 * @param arr2 * @return */ private int solution3(int[] arr1, int[] arr2){ // 注意 n1<=n2 -> 确保j>=0 int n1 = arr1.length; int n2 = arr2.length; if(n1 > n2){ return solution3(arr2, arr1); } int left = 0, right = n1; // preMax: 前一部分的最大值 // postMin: 后一部分的最小值 int preMax = 0, postMin = 0; // 二分 while (left <= right) { // 前一部分包含 arr1[0 .. i-1] 和 arr2[0 .. j-1] // 后一部分包含 arr1[i .. n1-1] 和 arr2[j .. n2-1] int i = (left+right)/2; int j = (n1+n2+1)/2 - i; // arr1_i_1, arr1_i, arr2_j_1, arr2_j 分别表示 arr1[i-1], arr1[i], arr2[j-1], arr2[j] int arr1_i_1 = (i==0?Integer.MIN_VALUE:arr1[i-1]); int arr1_i = (i==n1?Integer.MAX_VALUE:arr1[i]); int arr2_j_1 = (j==0?Integer.MIN_VALUE:arr2[j-1]); int arr2_j = (j==n2?Integer.MAX_VALUE:arr2[j]); if(arr1_i_1 <= arr2_j){ preMax = Math.max(arr1_i_1, arr2_j_1); postMin = Math.min(arr1_i, arr2_j); left = i + 1; }else{ right = i - 1; } } return preMax; } /** * 堆: 小根堆 + 大根堆 * @param arr1 * @param arr2 * @return */ private int solution4(int[] arr1, int[] arr2){ int n1 = arr1.length; int n2 = arr2.length; // 小根堆 PriorityQueue<Integer> minHeap=new PriorityQueue<>((a,b)->a-b); // 大根堆 PriorityQueue<Integer> maxHeap=new PriorityQueue<>((a,b)->b-a); for(int i=0; i<n1; i++){ if(maxHeap.isEmpty() || arr1[i]<maxHeap.peek()){ maxHeap.add(arr1[i]); if(maxHeap.size() > minHeap.size()+1){ minHeap.add(maxHeap.poll()); } }else{ minHeap.add(arr1[i]); if(minHeap.size() > maxHeap.size()){ maxHeap.add(minHeap.poll()); } } } for(int i=0; i<n2; i++){ if(maxHeap.isEmpty() || arr2[i]<maxHeap.peek()){ maxHeap.add(arr2[i]); if(maxHeap.size() > minHeap.size()+1){ minHeap.add(maxHeap.poll()); } }else{ minHeap.add(arr2[i]); if(minHeap.size() > maxHeap.size()){ maxHeap.add(minHeap.poll()); } } } return maxHeap.peek(); } }