import java.util.*;
/**
* NC413 两个升序数组的中位数
* @author d3y1
*/
public class Solution {
private int n;
private int m;
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 相似 -> NC36 在两个长度相等的排序数组中找到上中位数 [nowcoder]
*
* @param nums1 int整型ArrayList
* @param nums2 int整型ArrayList
* @return double浮点型
*/
public double Median (ArrayList<Integer> nums1, ArrayList<Integer> nums2) {
return solution1(nums1, nums2);
// return solution2(nums1, nums2);
// return solution3(nums1, nums2);
}
/**
* 二分
* @param nums1
* @param nums2
* @return
*/
private double solution1(ArrayList<Integer> nums1, ArrayList<Integer> nums2){
n = nums1.size();
m = nums2.size();
int k = (n+m)/2+1;
// 奇数
if((n+m)%2 == 1){
return getKthNum(k, nums1, nums2);
}
// 偶数
else{
return (getKthNum(k-1, nums1, nums2)+getKthNum(k, nums1, nums2))/2.0;
}
}
/**
* 获取第K小的元素
* @param k
* @param nums1
* @param nums2
* @return
*/
private int getKthNum(int k, ArrayList<Integer> nums1, ArrayList<Integer> nums2){
int left1 = 0;
int left2 = 0;
int mid1,mid2;
int half;
while(true){
if(left1 == n){
return nums2.get(left2+k-1);
}
if(left2 == m){
return nums1.get(left1+k-1);
}
if(k == 1){
return Math.min(nums1.get(left1), nums2.get(left2));
}
half = k/2-1;
mid1 = (left1+half)<n ? left1+half : n-1;
mid2 = (left2+half)<m ? left2+half : m-1;
if(nums1.get(mid1) <= nums2.get(mid2)){
k -= (mid1-left1+1);
left1 = mid1+1;
}else{
k -= (mid2-left2+1);
left2 = mid2+1;
}
}
}
/**
* 二分
* @param nums1
* @param nums2
* @return
*/
private double solution2(ArrayList<Integer> nums1, ArrayList<Integer> nums2){
n = nums1.size();
m = nums2.size();
if(n <= m){
return divideArray(nums1, nums2);
}else{
return divideArray(nums2, nums1);
}
}
/**
* 划分数组
* @param nums1
* @param nums2
* @return
*/
private double divideArray(ArrayList<Integer> nums1, ArrayList<Integer> nums2){
// 注意 n1<=n2 -> 确保j>=0
int n1 = nums1.size();
int n2 = nums2.size();
int left = 0;
int right = n1;
int i,j;
int nums1_i_1,nums1_i,nums2_j_1,nums2_j;
int preMax=0,postMin=0;
while(left <= right){
// 前一部分包含 nums1[0 .. i-1] 和 nums2[0 .. j-1]
// 后一部分包含 nums1[i .. n1-1] 和 nums2[j .. n2-1]
i = (left+right)/2;
j = (n1+n2+1)/2-i;
nums1_i_1 = (i==0) ? Integer.MIN_VALUE : nums1.get(i-1);
nums1_i = (i==n1) ? Integer.MAX_VALUE : nums1.get(i);
nums2_j_1 = (j==0) ? Integer.MIN_VALUE : nums2.get(j-1);
nums2_j = (j==n2) ? Integer.MAX_VALUE : nums2.get(j);
if(nums1_i_1 <= nums2_j){
preMax = Math.max(nums1_i_1, nums2_j_1);
postMin = Math.min(nums1_i, nums2_j);
left = i+1;
}else{
right = i-1;
}
}
return (n1+n2)%2==1 ? preMax : (preMax+postMin)/2.0;
}
/**
* 双指针
* @param nums1
* @param nums2
* @return
*/
private double solution3(ArrayList<Integer> nums1, ArrayList<Integer> nums2){
n = nums1.size();
m = nums2.size();
int k = (n+m)/2+1;
boolean isEven = (n+m)%2==0;
int count = 0;
double result = 0;
int min;
for(int i=0,j=0; i<n||j<m;){
if(i == n){
min = nums2.get(j++);
}else if(j == m){
min = nums1.get(i++);
}else{
if(nums1.get(i) < nums2.get(j)){
min = nums1.get(i++);
}else{
min = nums2.get(j++);
}
}
count++;
if(count == k-1){
if(isEven){
result += min;
}
}
if(count == k){
result += min;
if(isEven){
result /= 2.0;
}
break;
}
}
return result;
}
}