c语言数组排序后找出中位数,4. 寻找两个正序数组的中位数(LeetCode)——c语言...

方法一、暴力解法

简单说一下思路: 即先将两个数组合并为一个数组,然后对合并后的数组排序,最后求出排好序的数组的中位数。这种方法很暴力,没有利用两个子数组是有序的这一条件。合并两个数组时间复杂度O(m+n),排序一般使用快速排序,时间复杂度O((m+n)lg(m+n)),最终的时间复杂度取决于排序算法的时间复杂度,即最终时间复杂度是O((m+n)lg(m+n))。空间复杂度是O(m+n),因为要开辟额外空间存储两个数组。

方法二、借鉴归并排序的归并阶段,将两个有序数组归并为一个有序数组,然后根据数组长度奇偶性,求得相应的中位数。算法时间复杂度较优秀(O(m+n)),空间复杂度为O(m+n),和暴力解法一样。但时间复杂度还没有达到题目所要求的对数级别。

具体思路如下:

先将两个有序数组合并为一个有序数组,然后求得此有序数组的中位数。因此算法的核心是归并两个有序数组,可以借鉴归并排序里归并两个有序数组的方法。此法时间复杂度为O(m+n),因为需要遍历两个数组所有元素,空间复杂度为O(m+n),因为需要开辟新数组存储这两个数组的所有元素。#include

#include

double findMedianSortedArr(int *arr1, int arr1Size, int *arr2, int arr2Size)

{

//merge array

int size = arr1Size + arr2Size;

int *arr = (int *)malloc(size * sizeof(int));

int arr1Index = 0;

int arr2Index = 0;

double median;

for (int index = 0; index < size; index++) {

if (arr1Index < arr1Size && arr2Index < arr2Size)

{

if (arr1[arr1Index] <= arr2[arr2Index])

{

arr[index] = arr1[arr1Index];

arr1Index++;

}

else

{

arr[index] = arr2[arr2Index];

arr2Index++;

}

}

else if (arr1Index < arr1Size && arr2Index >= arr2Size)

{

arr[index] = arr1[arr1Index];

arr1Index++;

}

else if (arr1Index >= arr1Size && arr2Index < arr2Size)

{

arr[index] = arr2[arr2Index];

arr2Index++;

}

}

// 打印合并后的数组,测试的代码,可以注释掉

//for (int j = 0; j < size; j++) {

// printf("%d ", arr[j]);

//}

if (size % 2 == 0)

{

median = (double)(arr[size / 2 - 1] + arr[size / 2]) / 2;

}

else

{

median = arr[size / 2];

}

return median;

}

int main(void)

{

int arr1[] = {2, 4, 5, 7, 9, 29, 67};

int arr2[] = {3, 6, 8, 9, 10, 13, 18};

int size1 = sizeof(arr1) / sizeof(*arr1);

int size2 = sizeof(arr2) / sizeof(*arr2);

printf("arr length: %d %d\n", size1, size2);

double median = findMedianSortedArr(arr1, size1, arr2, size2);

printf("\n");

for (int i = 0; i < size1; i++)

{

printf("%d ", arr1[i]);

}

printf("\n");

for (int j = 0; j < size2; j++)

{

printf("%d ", arr2[j]);

}

printf("\n");

printf("median is %f", median);

printf("\n");

}方法一和方法二思路一样,都是先合并数组为一个有序数组,再求出中位数。

方法三:二分法查找数组划分线。我们不必合并数组,而是去寻找数组的划分线,使得划分之后的数组满足如下性质:划分线左边的所有数值都小于划分线右边的所有数值

划分线两边数字相等(两个数组长度之和为偶数)或者左边比右边多1个数字(两个数组长度之和为奇数)

那么,两个数组长度之和为偶数时:划分线左边的最大值与划分线右边的最小值的平均数就是我们要找的中位数。

两个数组长度之和为奇数时,划分线左边的最大值就是我们要找的中位数。

因此,我们的主要任务是寻找划分线,再寻找划分线时使用二分查找。

需要注意的是,我们只需要确定一个数组上的划分线,然后根据上述性质,即可确定另一个数组上的划分线。#include

#include

double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size){

if (nums1Size > nums2Size) {

int* temp = nums1;

nums1 = nums2;

nums2 = temp;

int tempNum = nums1Size;

nums1Size = nums2Size;

nums2Size = tempNum;

}

int left = 0;

int right = nums1Size;

int bothLeftLen = (nums1Size + nums2Size + 1) / 2;

int i, j;

while (left < right) {

i = left + (right - left + 1) / 2;

j = bothLeftLen - i;

if (nums1[i - 1] > nums2[j]) {

right = i - 1;

} else {

left = i;

}

}

i = left;

j = bothLeftLen - i;

int leftNums1Max = i == 0 ? INT_MIN : nums1[i - 1];

int rightNums1Min = i == nums1Size ? INT_MAX : nums1[i];

int leftNums2Max = j == 0 ? INT_MIN : nums2[j - 1];

int rightNums2Min = j == nums2Size ? INT_MAX : nums2[j];

int leftMax = leftNums1Max > leftNums2Max ? leftNums1Max : leftNums2Max;

int rightMin = rightNums1Min < rightNums2Min ? rightNums1Min : rightNums2Min;

if ((nums1Size + nums2Size) % 2 == 0)

{

return (double)(leftMax + rightMin) / 2;

}

else

{

return leftMax;

}

}

int main () {

int arr1[] = {2, 4, 5};

int arr2[] = {1, 3};

int len1 = sizeof(arr1) / sizeof(*arr1);

int len2 = sizeof(arr2) / sizeof(*arr2);

double median = findMedianSortedArrays(arr1, len1, arr2, len2);

printf("%f", median);

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值