1. 题目描述
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。
请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。
你可以假设 nums1 和 nums2 不同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
2.代码如下
初步思路:先排序后求中位数
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {
int i,j;
int n = nums1Size + nums2Size;
int temp;
int tempn;
int *num3 = (int*)malloc(sizeof(int)*n);//给数组分配内存
memset(num3,0,sizeof(num3));
//先排序,将两者合并成一个有序数组
for (i=0;i < nums1Size;i++)//注意边界条件
{
*(num3+i) = *(nums1+i);
}
for(j=0;j < nums2Size;j++)//注意边界条件
{
*(num3+j+nums1Size) = *(nums2+j);
}
//合并好后排序,采用冒泡排序法进行排序
for(j = 0 ;j < n ;j ++)
{
for(i = j+1 ; i < n ;i++)//一定要注意边界条件
{
temp = *(num3+j);
tempn = *(num3+i);
if(temp > tempn)//交换两者的值
{
*(num3+j) = tempn;
*(num3+i) = temp;
}
}
}
//冒泡排序的思想就是:
/* 将每一轮遍历的第一个元素与第二个元素开始直到最后的元素相比较,
大于则交换,然后继续比较,要搞清楚的是,换值不换序,我是依据按序来取值比较,
即使我比较的过程中会交换不同序号上的值,但是我的序号是没有变的
*/
int up = n/2;
int test = n%2;
double num = 0;
if(test==0)//偶数
{
int down = up -1;
num = num3[up]+num3[down];
num = num/2;
free(num3);
return num;
}
else//奇数
{
num = num3[up];
free(num3);
return num;
}
return 0;
}
//本题目用的是冒泡排序,时间复杂度为T(n^2),空间复杂度为O(m+n);
//提交居然通过了??
优化时空复杂度
思路
首先,求一个长度为N的增序数组nums的中位数,
若N为偶数,则中位数为 (nums[(N/2)-1] + nums[N/2]) / 2,需要计算两个位置(N/2)- 1 ,N/2 处的数
若N为奇数,则中位数为 nums[N/2],只需要计算位置N/2处的数
其次,题目给我们的是两个增序数组,长度为n,m,而且还要求算法时空复杂度为O(n+m),也就是每个数组只能被遍历一次。
那么就直接联想到合并两个增序链表的处理方法,只不过在遍历的过程中,通过计数器判断是否在"合并"过程中得到了我们所要的位置的数即可。
解题方法
通过"合并"两个增序数组的过程,取处我们要的中位数的
复杂度
时间复杂度: O(n+m)
空间复杂度:
添加空间复杂度, 示例: O(1)O(1)
O(1)
/*
* date 2024-06-12
* author zhangyb
* city hangzhou
*/
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int allCnt = (int)nums1.size() + (int)nums2.size();
//判断我们要从合并后的数组的何处开始取中位数
int idx = allCnt / 2;
int neededNums = 0;
//通过两数组的长度判断我们要取出几个数来计算中位数
if (allCnt % 2 == 1) {
neededNums = 1;
}
else {
idx -= 1;//如果合并后是偶数长度,则应该取: (N/2)- 1 ,N/2 这两个位置的中位数
neededNums = 2;
}
int l1 = 0;
int r1 = nums1.size() - 1;
int l2 = 0;
int r2 = nums2.size() - 1;
int cnt = 0;
int sum = 0;
int size = neededNums;
//进行"合并",我们并不需要真合并,只需要计数器判断处当前顺序是否是我们要的数
while (l1 <= r1 && l2 <= r2) {
if (nums1[l1] <= nums2[l2]) {
if (cnt >= idx && size) {//cnt是计数器,idx是要取的数的起始位置,size则是需要取的数的个数
sum += nums1[l1];
size -= 1;
}
l1++;
}
else {
if (cnt >= idx && size) {
sum += nums2[l2];
size -= 1;
}
l2++;
}
cnt++;
}
if (size == 0) {
return (double)sum / neededNums;
}
while (l1 <= r1) {
if (cnt >= idx && size) {
sum += nums1[l1];
size -= 1;
}
l1++;
cnt++;
if (size == 0) {
return (double)sum / neededNums;
}
}
while (l2 <= r2) {
if (cnt >= idx && size) {
sum += nums2[l2];
size -= 1;
}
l2++;
cnt++;
if (size == 0) {
return (double)sum / neededNums;
}
}
return 0;
}
};
int main () {
std::vector<int> nums1 = {1, 3, 5, 7, 9};
std::vector<int> nums2 = {2, 4, 6, 8, 10};
Solution slu;
std::cout << slu.findMedianSortedArrays(nums1, nums2) << "\n";
return 0;
}