LeetCode:4.两个排序数组的中位数

题目

LeetCode:Median of Two Sorted Arrays

给定两个大小为 m 和 n 的有序数组 nums1nums2

请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。

示例:

示例1:

nums1 = [1, 3]
nums2 = [2]
中位数是 2.0

示例2:

nums1 = [1, 2]
nums2 = [3, 4]
中位数是 (2 + 3)/2 = 2.5

思路

本来可以归并排序,直接求中位数,但是由于有时间复杂度要求,所以采用快排的思想找中位数。
快速排序的思想是分治,将一个数组分成两块之后再进行排序,也就是说,如果采用分治,由于中位数的下标是固定的,当划分点的下标 < 中位数下标,此时就去划分点右边去找,反之就去左边,和二分查找的方式很像,这种查找方式的时间复杂度正好为log(m + n)。
我们要做的就是先把数组合并,然后用快排的思想进行分区,直至分区下标 = 中位数下标,此方法也可以找无序数组的中位数。

代码

查看更多LeetCode代码

int QuickMove(int* arr, int left, int right);//快排思想找中位数
void Swap(int* x1, int * x2);//交换函数

double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {
    //此方法可以找两个无序数组的中位数
    assert(nums1 && nums2);
    int* num;
    int size = nums1Size + nums2Size;
    int div = 0;
    double ret = 0;
    //开辟一个新数组将两数组合二为一
    num = (int*)malloc(sizeof(int) * (nums1Size + nums2Size));
    memcpy(num, nums1, sizeof(int) * nums1Size);
    memcpy(num + nums1Size, nums2, sizeof(int) * nums2Size);
    div = QuickMove(num, 0, size - 1);//首先将查找的部分用QuickMove分块
    while (div != size / 2)//不论数个数为奇数还是偶数个,size / 2下标的数均需要找
    {
        if (div < size / 2)
        {
            div = QuickMove(num, div + 1, size - 1);
        }
        else
        {
            div = QuickMove(num, 0, div - 1);
        }
    }
    ret = (double)num[div];
    if (size % 2 == 0)
    {
        //数组个数为偶数,需要找下标为(size - 1) / 2的数,两数相加除以二即中位数
        while (div != (size - 1) / 2)
        {
            if (div < (size - 1) / 2)
            {
                div = QuickMove(num, div + 1, size - 1);
            }
            else
            {
                div = QuickMove(num, 0, div - 1);
            }
        }
        ret += (double)num[div];
        free(num);//释放掉申请的空间,不能忘
        return ret / 2;
    }
    free(num);
    return ret;
}

int QuickMove(int* arr, int left, int right)
{
    //assert(arr && left < right);
    //此处注释部分解释一下,上面部分left有可能会和right相等传进来报错
    //下面部分本来想得到left和right以及mid(数组中间的数)的中位数来作为标准区分快排分区,结果造成死循环
    //int mid = GetMid(arr, left, right);
    //Swap(arr + mid, arr + right);*
    int key = arr[right];
    int fast = left;
    int slow = left - 1;
    while (fast < right)
    {
        if (arr[fast] <= key)
        {
            slow++;
            if (slow != fast)
            {
                Swap(arr + fast, arr + slow);
            }
        }
        fast++;
    }
    slow++;
    Swap(arr + slow, arr + right);
    return slow;
}

void Swap(int* x1, int * x2)
{
    if (x1 == x2)
    {
        return;
    }
    *x1 ^= *x2;
    *x2 ^= *x1;
    *x1 ^= *x2;
}
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值