题解 | #牛的体重排序# 分治解法
牛的体重排序
https://www.nowcoder.com/practice/1afd5afef2aa49a8a39b63bb9d2821f9
知识点
递归 分治
思路
两个有序数组,一个长度为n,一个长度为m,找到两个数组归并后的中位数。
根据中位数的定义,假如是奇数,那么需要找到第
小的数作为答案;假如是偶数,那么需要找到第
小的数和
小的数的平均数作为中位数。
因此我们需要实现一个函数find可以在log时间内找到两个有序数组的第k小的数。
对于找两个有序数组的第k小数的函数 find(vector<int>& nums1, int i, vector<int>& nums2, int j, int k):
其中i是第一个数组第一个可以选的位置, j是第二个数组第一个可以选的位置
首先,假如两个有序数组中的剩余未选的元素个数均大于等于k/2,那么我们先在两个数组的剩余元素中先各选k/2个
- 如果在nums1数组中本次选出的k/2个元素的最大元素大于nums2数组本次选出的k/2个元素的最大元素,这说明nums2应该再多选点,nums1应该少选点,进一步我们知道nums2这k/2个元素是一定要选出的,那么下一次只需要在剩余的元素中选出
k - k/2个元素,问题规模变成了原问题的一半
- 假如不满足上面这一条,那么nums1的这k/2个元素是一定要选出的,那么下一次只需要在剩余的元素中选出k - k/2个元素,问题规模变成了原问题的一半
考虑边界情况,假如有一个数组不足够取k/2个元素了,那么把剩余的元素全取;当k=1时选取两个数组中可以选择的最小元素即可
实现上始终让nums1作为备选元素少的一个数组用来简化计算。
时间复杂度
由于用分治思想,每次可以解决原问题的一半,时间复杂度为
AC code (C++)
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param weightsA int整型vector
* @param weightsB int整型vector
* @return double浮点型
*/
double findMedianSortedArrays(vector<int>& weightsA, vector<int>& weightsB) {
// write code here
int tot = weightsA.size() + weightsB.size();
if (!(tot & 1)) {
int left = find(weightsA, 0, weightsB, 0, tot / 2);
int right = find(weightsB, 0, weightsA, 0, tot / 2 + 1);
return (left + right) / 2.0;
}
return find(weightsA, 0, weightsB, 0, tot / 2 + 1);
}
double find(vector<int>& nums1, int i, vector<int>& nums2, int j, int k) {
if (nums1.size() - i > nums2.size() - j) return find(nums2, j, nums1, i, k);
if (k == 1) {
if (nums1.size() == i) return nums2[j];
else return min(nums1[i], nums2[j]);
}
if (nums1.size() == i) return nums2[j + k - 1];
int si = min(i + k / 2, (int)nums1.size()), sj = j + k - k / 2;
if (nums1[si - 1] > nums2[sj - 1]) return find(nums1, i, nums2, sj, k - (sj - j));
else return find(nums1, si, nums2, j, k - (si - i));
}
};

