算法题(程序员面试宝典)
解题思路主要来源于leetcode官方与《程序员面试宝典》。
4. 寻找两个正序数组的中位数
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:
输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:
输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:
输入:nums1 = [2], nums2 = []
输出:2.00000
解题方法
思路来源:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-2/
解题思路1
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
//合并数组,再找中位数
int m = nums1.length;
int n = nums2.length;
//特殊情况,一方长度为0,直接返回
if(m==0){
if(nums2.length%2==0){
return (nums2[(nums2.length/2)-1]+nums2[nums2.length/2])/2.0;
}else{
return nums2[nums2.length/2];
}
}
if(n==0){
if(nums1.length%2==0){
return (nums1[(nums1.length/2)-1]+nums1[nums1.length/2])/2.0;
}else{
return nums1[nums1.length/2];
}
}
//合并数组
int[] nums = new int[nums1.length+nums2.length];
int count = 0;
int i=0,j=0;
while(count!=(m+n)){
if(i==m){
//nums1 数组已遍历结束
while(j!=n){
nums[count++]=nums2[j++];
}
break;
}
if(j==n){
//nums2 数组已遍历结束
while(i!=m){
nums[count++]=nums1[i++];
}
break;
}
if(nums1[i]>nums2[j]){
nums[count++] = nums2[j++];
}else{
nums[count++] = nums1[i++];
}
}
//返回中位数
if((m+n)%2==0){
return (nums[((m+n)/2)-1]+nums[(m+n)/2])/2.0;
}else{
return nums[(m+n)/2];
}
}
}
解题思路2
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
//双指针思想
int m = nums1.length;
int n = nums2.length;
int len = m+n;
// 存储中位数的值
int left = -1,right = -1;
// 遍历数组的指针
int aStart = 0,bStart = 0;
for(int i = 0;i<=(len/2);i++){
//更新left的值
left = right;
if(aStart<m&&(bStart>=n||nums1[aStart]<nums2[bStart])){
//1 nums1未遍历结束且nums1[aStart]<nums2[bStart]
//2 nums1未遍历结束且nums2遍历结束
right = nums1[aStart++];
}else{
right = nums2[bStart++];
}
}
if(len%2==0){
return (left+right)/2.0;
}else{
return right;
}
}
}
解题思路3
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
//二分思想 将问题转换为找第k个小数 (递归解法)
int m = nums1.length;
int n = nums2.length;
int left = (m+n+1)/2;
int right = (m+n+2)/2;
return (getKth(nums1,0,m-1,nums2,0,n-1,left)+getKth(nums1,0,m-1,nums2,0,n-1,right))*0.5;
}
public int getKth(int[] nums1,int astart,int aend,int[] nums2,int bstart,int bend,int k){
int len1 = aend - astart +1;
int len2 = bend - bstart +1;
//让 len1 的长度小于 len2,这样就能保证如果有数组空了,一定是 len1
if(len1>len2)
return getKth(nums2,bstart,bend,nums1,astart,aend,k);
// 数组1为空时,返回数组2的第k个小数
if(len1==0)
return nums2[bstart+k-1];
if(k==1)
return Math.min(nums1[astart],nums2[bstart]);
//每次淘汰 k/2 个值小的数(当长度不够k/2时,排除len个 值小的数)
int i = astart + Math.min(len1,k/2) -1;
int j = bstart + Math.min(len2,k/2) -1;
if(nums1[i]>nums2[j]){
return getKth(nums1,astart,aend,nums2,j+1,bend,k-(j-bstart+1));
}else{
return getKth(nums1,i+1,aend,nums2,bstart,bend,k-(i-astart+1));
}
}
}