二分思想递归解决寻找两个正序数组的中位数

本文介绍如何使用双指针技巧解决有序数组合并问题,求解总长度为偶数时的第k个和第k+1个元素作为中位数。通过递归的findK函数实现查找操作,适用于编程竞赛和算法面试题.

两个数组一个长度为m,一个长度为n,总长度total=m+n,k=(total/2)。由于两个数组是有序的,所以我们只需要找到两个数组中的第k+1个元素(总长度为偶数的时候,还要找到第k个元素)。

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int total = nums1.size() + nums2.size();
        if(total % 2 == 0){
            int left = findK(nums1, 0, nums2, 0, total/2);
            int right = findK(nums1, 0, nums2, 0, total/2+1);
            return (left+right)/2.0;
        }
        else{
            return findK(nums1, 0, nums2, 0, total/2+1);
        }
    }
    int findK(vector<int>& nums1, int i, vector<int>& nums2, int j, int k){
        if(nums1.size()-i > nums2.size()-j) return findK(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((int)nums1.size(), i+k/2);
        int sj = j+k/2;
        //若nums[sj-1]小,0————sj-1的元素就舍弃掉
        if(nums1[si-1] > nums2[sj-1]){
            return findK(nums1, i, nums2, sj, k-(sj-j));
        }
        //若nums[si-1]小,0————si-1的元素就舍弃掉
        else{
            return findK(nums1, si, nums2, j, k-(si-i));
        }
    }
};

### 问题分析 给定两个长度为 $N$ 的升序整型数 $A$ 和 $B$,目标是找出这两个合并后形成的升序数中位数。由于数长度相同且已排序,可以利用二分查找的思想设计一个时间复杂度为 $O(\log N)$ 的高效算法。 合并后的数长度为 $2N$,因此中位数是合并数中第 $N$ 个元素(下中位数)。 ### 算法思路 该问题可以通过对两个进行二分查找来实现: - 每次在两个中各取一个中间位置的元素进行比较。 - 如果 $A[mid] < B[mid]$,说明中位数不可能在 $A$ 的前半部分,也不在 $B$ 的后半部分。 - 反之,如果 $A[mid] > B[mid]$,说明中位数不可能在 $B$ 的前半部分,也不在 $A$ 的后半部分。 - 每次递归缩小查找范围,直到找到中位数。 ### C语言实现 ```c #include <stdio.h> int findMedian(int A[], int B[], int leftA, int rightA, int leftB, int rightB) { // 当只剩下一个元素时,取较小的那个 if (leftA == rightA) { return (A[leftA] < B[leftB]) ? A[leftA] : B[leftB]; } int midA = (leftA + rightA) / 2; int midB = (leftB + rightB) / 2; // 比较两个中位数 if (A[midA] == B[midB]) { return A[midA]; // 相等时即为中位数 } else if (A[midA] < B[midB]) { // A的中位数小于B的中位数,舍弃A的前半部分和B的后半部分 return findMedian(A, B, midA + 1, rightA, leftB, midB); } else { // A的中位数大于B的中位数,舍弃B的前半部分和A的后半部分 return findMedian(A, B, leftA, midA, midB + 1, rightB); } } int main() { int A[] = {11, 13, 15}; int B[] = {6, 8, 20}; int N = sizeof(A) / sizeof(A[0]); int median = findMedian(A, B, 0, N - 1, 0, N - 1); printf("两个序数中位数为: %d\n", median); return 0; } ``` ### 示例说明 - 输入数 `A = {11, 13, 15}` 和 `B = {6, 8, 20}`。 - 合并后的数为 `{6, 8, 11, 13, 15, 20}`。 - 中位数是第3个元素,即 `11`。 ### 时间复杂度分析 该算法采用分治策略,每次将问题规模减半,因此时间复杂度为 $O(\log N)$,空间复杂度为 $O(1)$(不考虑递归栈空间)。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值