https://leetcode.cn/problems/median-of-two-sorted-arrays/
归并排序的思想,因为nums1和nums2已经是有序的,所以把两个数组中的结果放到一个新的数组中,检查index是否已经指向中位数的位置,如果是的话,在根据nums1和nums2两个数组长度总和是奇数还是偶数进行判断,是直接返回一个数值,还是两个数加和求平均再返回
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int totalLength = nums1.length + nums2.length;
int[] nums = new int[totalLength];
int i = 0, j = 0;
int index = 0;
while (i < nums1.length && j < nums2.length) {
if (nums1[i] < nums2[j]) {
nums[index] = nums1[i++];
} else if (nums1[i] > nums2[j]) {
nums[index] = nums2[j++];
} else {
nums[index] = nums1[i++];
}
if (index == totalLength / 2) {
//nums数组长度为偶数
if ((totalLength & 1) == 0) {
return (nums[index] + nums[index - 1]) / 2.0;
} else {
//nums数组长度是奇数
return 1.0 * nums[index];
}
}
index++;
}
if (i == nums1.length) {
while (j <= nums2.length) {
nums[index] = nums2[j++];
if (index == totalLength / 2) {
//nums数组长度为偶数
if ((totalLength & 1) == 0) {
return (nums[index] + nums[index - 1]) / 2.0;
} else {
//nums数组长度是奇数
return 1.0 * nums[index];
}
}
index++;
}
}
if (j == nums2.length) {
while (i < nums1.length) {
nums[index] = nums1[i++];
if (index == totalLength / 2) {
//nums数组长度为偶数
if ((totalLength & 1) == 0) {
return (nums[index] + nums[index - 1]) / 2.0;
} else {
//nums数组长度是奇数
return 1.0 * nums[index];
}
}
index++;
}
}
return 0.0;
}
}
就代码而言,感觉还是有一定的冗余,不精炼
先将两个数组合并,两个有序数组的合并也是归并排序的一部分,然后根据是奇数、还是偶数,返回中位数
和我的思路一样,不过代码看上去更简洁一些
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
//如果nums1数组的长度为0,只要返回nums2数组的中位数即可
if (m == 0) {
if ((n & 1) != 0) {
return nums2[n / 2];
} else {
return (nums2[n / 2] + nums2[n / 2 - 1]) / 2.0;
}
} else if (n == 0) {
if ((m & 1) != 0) {
return nums1[m / 2];
} else {
return (nums1[m / 2] + nums1[m / 2 - 1]) / 2.0;
}
}
int count = 0;
int i = 0, j = 0;
int[] nums = new int[m + n];
while (count != (m + n)) {
if (i == m) {
while (j != n) {
nums[count++] = nums2[j++];
}
break;
}
if (j == n) {
while (i != m) {
nums[count++] = nums1[i++];
}
break;
}
if (nums1[i] < nums2[j]) {
nums[count++] = nums1[i++];
} else {
nums[count++] = nums2[j++];
}
}
if ((count & 1) != 0) {
return nums[count / 2];
}
return (nums[count / 2] + nums[count / 2 - 1]) / 2.0;
}
}
遍历整个数组,O(m+n)
开辟了一个数组,保存两个数组合并以后的结果O(m+n)
如何将奇数和偶数的情况合并?
用len表示合并后数组的长度
如果是奇数,需要知道l第en/2+1个数字是什么,需要遍历len/2+1个数
如果是偶数,需要知道第len/2个数字和第len/2+1个数字是什么,也需要遍历len/2+1个数
用两个变量,pre和now,now保存当前循环的结果,在每次循环前将now的值赋值给pre。这样在最后一次循环的时候,pre将得到right的值,也就是上一次循环的结果,接下来,now更新为最后一次的结果
循环中,分别用aStart和bStart分别表示当前指向nums1数组和nums2数组的位置。
如果aStart没有到最后,并且nums1中aStart位置上的数字小于nums2中bStart位置上的数字,那么,aStart可以往后移,也就是 aStart < m && nums1[aStart] < nums2[bStart]。
上面的条件表达式,如果nums2数组已经遍历到头了,再取nums2[bStart]会数组越界,抛出异常,所以,要判断一下bStart是否大于等于nums2的数组长度,这样 || 后面的nums1[aStart] < nums2[bStart]就不会执行了,也就不会导致错误了。所以,增加为 aStart < m && (bStart >= n || nums1[aStart] < nums2[bStart])
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int len = m + n;
int aStart = 0, bStart = 0;
int pre = -1, now = -1;
for (int i = 0; i <= len / 2; i++) {
pre = now;
if (aStart < m && (bStart >= n || nums1[aStart] < nums2[bStart])) {
now = nums1[aStart++];
} else {
now = nums2[bStart++];
}
}
if ((len & 1) != 1) {
return (pre + now) / 2.0;
}
return now * 1.0;
}
}
遍历len/2+1次,len=m+n,所以,时间复杂度依旧是O(m+n)
申请了常数个变量,所以是O(1)