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();
}
}