合并两个有序数组(C Language)

题目

88. 合并两个有序数组 - 力扣(Leetcode)https://leetcode.cn/problems/merge-sorted-array/

思路1:直接合并后排序

最直观的方法是先将数组nums2放进数组nums1的尾部,然后直接对整个数组进行排序

时间复杂度为O((m+n)log(m+n)),排序序列长度为m+n,套用快速排序的时间复杂度即可,平均情况为O((m+n)log(m+n))

空间复杂度为O((m+n)log(m+n)),排序序列长度为m+n,套用快速排序的空间复杂度即可,平均情况为O((m+n)log(m+n))

void Swap(int arr[], int low, int high)
{
    int temp;
    temp = arr[low];
    arr[low] = arr[high];
    arr[high] = temp;
}

int Partition(int arr[], int low, int high)
{
    int base = arr[low];
    while (low < high)
    {
        while (low < high && arr[high] >= base)
        {
            high--;
        }
        Swap(arr, low, high);
        while (low < high && arr[low] <= base)
        {
            low++;
        }
        Swap(arr, low, high);
    }
    return low;
}

void QuickSort(int arr[], int low, int high)
{
    if (low < high)
    {
        int base = Partition(arr, low, high);
        QuickSort(arr, low, base - 1);
        QuickSort(arr, base + 1, high);
    }
}

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    int i, j;
    for (i = m, j = 0; j < n; j++, i++)
    {
        nums1[i] = nums2[j];
    }
    QuickSort(nums1, 0, m + n - 1);
}

思路2:开辟额外的数组

思路1没有利用数组nums1与nums2已经被排序的性质。为了利用这一性质,我们可以使用双指针方法。这一方法将两个数组看作队列,每次从两个数组头部取出比较小的数字放到结果中

时间复杂度:O(m+n)。指针移动单调递增,最多移动m+n次,因此时间复杂度为O(m+n)。 

空间复杂度:O(m+n)。需要建立长度为m+n的中间数组sorted。 

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    int* sorted = (int*)malloc(sizeof(int) * nums1Size);
    int p1 = 0;
    int p2 = 0;
    int cur = 0;
    while (p1 < m && p2 < n)
    {
        if (nums1[p1] > nums2[p2])
        {
            sorted[cur++] = nums2[p2++];
        }
        else
        {
            sorted[cur++] = nums1[p1++];
        }
    }
    if (p1 == m)
    {
        for (int i = p2; i < n; ++i)
        {
            sorted[cur++] = nums2[p2++];
        }
    }
    if (p2 == n)
    {
        for (int i = p1; i < m; ++i)
        {
            sorted[cur++] = nums1[p1++];
        }
    }
    for (int i = 0; i < nums1Size; ++i)
    {
        nums1[i] = sorted[i];
    }
    free(sorted);
    sorted = NULL;
}

思路3:从最大数开始逆向存储

思路2中,之所以要创建临时数组sorted,是因为如果直接合并到数组nums1中,nums1中的元素可能会在取出之前被覆盖。那么如何直接避免覆盖nums1中的元素呢?观察可知,nums1的后半部分是空的,可以直接覆盖而不会影响结果。

因此可以指针设置为从后向前遍历,每次取两者之中的较大者放进nums1的最后面

Note:

严格来说,在此遍历过程中的任意一个时刻,nums1数组中有m−end1−1个元素被放入nums1的后半部,nums2数组中有n−end2−1个元素被放入nums1的后半部。而在指针end1的后面,nums1数组有m+n−end1−1个位置。

由于m+n−end1−1≥m−end1−1+n−end2−1等价于p2≥−1永远成立,因此nums1后面的位置永远足够容纳被插入的元素,不会产生nums1的元素被覆盖的情况。

时间复杂度:O(m+n)。指针移动单调递减,最多移动m+n次,因此时间复杂度为O(m+n)

空间复杂度:O(1)。直接对数组nums1原地修改,不需要额外空间。

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    int end1 = m - 1;
    int end2 = n - 1;
    int end = m + n - 1;
    while (end1 >= 0 && end2 >= 0)
    {
        if (nums1[end1] > nums2[end2])
        {
            nums1[end--] = nums1[end1--];
        }
        else
        {
            nums1[end--] = nums2[end2--];
        }
    }
    while (end2 >= 0)
    {
        nums1[end--] = nums2[end2--];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少校0778

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值