Leetcode04寻找两个有序数组的中位数

问题描述:给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
思路

  • 暴力求解

.通过直接对数组遍历排序,从新数组中直接计算中位数。
时间复杂度:o(m+n)
空间复杂度:o(m+n)

  • 数组遍历

不对数组进行重新组合,直接在遍历过程中计算位置(分奇偶)。
时间复杂度:o(m+n)
空间复杂度:o(1)

  • 分支算法—第k小数

将中位数的寻找看成第k小数的寻找,并将奇偶情况转化为同一计算方式(把偶次中位数看成两次)。
时间复杂度:o(log(m + n))
空间复杂度:o(1)

  • 分支算法—对半分割思想

对两个数组分别进行切割,每次切除将数组分为两半,并且交叉拼接满足位数相同,直至找到这样的位置使得左边最大小于等于右边最小。
复杂度:与第三种方法相同

//c++
//方法一:暴力求解
class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        double median = 0.0;
        vector<int> num;
        int i = 0, j = 0;
        int len1 = nums1.size();
        int len2 = nums2.size();
        while(i < len1 & j < len2){
        //比较大小填入新数组
            if(nums1[i] <= nums2[j]){
                num.push_back(nums1[i]);
                ++i;
            }else{
                num.push_back(nums2[j]);
                ++j;
            }
        }
        //将剩余部分装入
       while(j <len2){
            num.push_back(nums2[j]);
            ++j;
        }
       while(i <len1){
            num.push_back(nums1[i]);
            ++i;
        }
        //直接寻找中位数
        if((len1 +len2)%2)
            median = num[floor((len1 + len2)/2.0)];
        else
            median = (num[(len1 + len2)/2] + num[(len1 + len2)/2 - 1])/2.0;
        return median;
    }
};
//方法二:数组遍历
class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        double median = 0.0;
        int index1 = 0, index2 = 0;//num1,num2遍历位置
        int len1 = nums1.size();
        int len2 = nums2.size();
        int len = len1 + len2;
        int left = -1, right = -1;
        //寻找中间位置,left保持上一次位置,当数组和为偶数时并入计算
        for(int i = 0; i <= len/2; ++i){
            left = right;
            if(index1 < len1 && (index2 >= len2 || nums1[index1] < nums2[index2]))
                right = nums1[index1++];
            else
                right = nums2[index2++];
        }
        //判断奇偶情况
        if(len%2)
            return right;
        else
            return (left + right)/2.0;
    }
};
//方法三:第k小数
class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int len1 = nums1.size();
        int len2 = nums2.size();
        //当数组和为奇数时下面两数相同,偶数是分别指向中位数左右两个位置
        int left = (len1 + len2 + 1)/2;
        int right = (len1 + len2 + 2)/2;
        //奇偶情况并入计算
        return (getKth(nums1, 0, len1-1, nums2, 0, len2-1, left) + getKth(nums1, 0, len1-1, nums2, 0, len2-1, right))/2.0;
    }
    //求第k小数
    int getKth(vector<int>& num1, int left1, int right1, vector<int>& num2, int left2, int right2 , int k){
        int size1 = right1 - left1 + 1;
        int size2 = right2 - left2 + 1;
        //保证第一个数组长度小于第二个
        if(size1 > size2) return getKth(num2, left2, right2, num1, left1, right1, k);
        //第一个数组筛选完毕,直接进入第二个数组找
        if(size1 == 0){
            return num2[left2 + k - 1];
        }else if(k == 1){
        //筛选到最后一位,找两个位置较小的数
            return num1[left1] <= num2[left2] ? num1[left1] : num2[left2];
        }else{
        //更新位置,筛掉较小的一部分数(k/2或数组剩余)
            int i = (size1 < k/2 ? size1 : k/2) + left1 - 1;
            int j = (size2 < k/2 ? size2 : k/2) + left2 - 1;
            //递归筛选至上述基本情况
            if(num1[i] <= num2[j])
                return getKth(num1, i + 1, right1, num2, left2, right2, k - (i - left1 + 1));
            else
                return getKth(num1, left1, right1, num2, j + 1, right2, k - (j - left2 + 1));
        }
    }
};
//方法四:分割思想
class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int len1 = nums1.size();
        int len2 = nums2.size();
        //保证j的范围
        if(len1 > len2) return findMedianSortedArrays(nums2, nums1);
        int left = 0, right = len1;
        while(left <= right){
        //找到i, j分别指向的数组位置
            int i = (left + right)/2;
            int j = (len1 + len2 + 1)/2 - i;
            //判断移动方向
            if(i < len1 && j > 0 && nums1[i] < nums2[j-1]){
                left = i + 1;
            }else if(i > 0 && j < len2 && nums1[i-1] > nums2[j]){
                right = i - 1;
            }else{
            //根据奇偶情况输出元素
                int maxleft;
                //移动到边界
                if(i == 0){
                    maxleft = nums2[j - 1];
                }else if(j == 0){
                    maxleft = nums1[i - 1];
                }else{
                //找到分界位置,判断左边最大元素
                    maxleft = (nums1[i - 1] > nums2[j - 1] ? nums1[i - 1]:nums2[j - 1]);
                }
                //奇数和输出单个元素
                if((len1 + len2)%2) return maxleft;
                //偶数和找到最小右元素
                int minright;
                if(i == len1){
                    minright = nums2[j];
                }else if(j == len2){
                    minright = nums1[i];
                }else{
                    minright = (nums1[i] < nums2[j]) ? nums1[i]:nums2[j];
                }
                return (maxleft + minright)/2.0;
            }
        }
        return 0.0;
    }
};
#python
#方法一:暴力求解
class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        lst = []
        i = j = 0
        while (i < len(nums1)) and (j < len(nums2)):
            if (nums1[i] > nums2[j]):
                lst.append(nums2[j])
                j += 1
            else:
                lst.append(nums1[i])
                i += 1
        if i < len(nums1):
            lst.extend(nums1[i:])
        else:
            lst.extend(nums2[j:])
        return (lst[int(len(lst)/2)] + lst[int((len(lst) - 1)/2)])/2 
'''也可直接通过sorted函数直接合并两列表并排序'''
#方法二:数组遍历
class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        left = right = 0 
        i = j = k = 0
        alen = len(nums1) + len(nums2)
        while k <= alen/2:
            left = right
            if i < len(nums1) and (j >= len(nums2) or (nums1[i] < nums2[j])):
                right = nums1[i]
                i += 1
            else:
                right = nums2[j]
                j += 1
            k += 1
        if alen%2:
            return right
        else:
            return (left + right)/2.0
#方法三:第k小数
def findMedianSortedArrays(nums1, nums2):
    len1 = len(nums1)
    len2 = len(nums2)
    left = int((len1 + len2 + 1) / 2)
    right = int((len1 + len2 + 2) / 2)
    return (getKth(nums1, nums2, left) + getKth(nums1, nums2, right)) / 2.0
def getKth(num1, num2, k):
    if len(num1) > len(num2): return getKth(num2, num1, k)
    if len(num1) == 0: return num2[k - 1]
    if k == 1: return min(num1[0], num2[0])
    i = int(min(len(num1), k/2)) - 1
    j = int(min(len(num2), k/2)) - 1
    if num1[i] <= num2[j]:
        if i + 1 < len(num1): return getKth(num1[i+1:], num2, k - i - 1)
        else: return getKth([], num2 ,k -i -1)
    else:
        return getKth(num1, num2[j+1:], k - j - 1)
#方法四:分割思想
class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        len1 = len(nums1)
        len2 = len(nums2)
        slen = len1 + len2
        if len1 > len2: return self.findMedianSortedArrays(nums2,nums1)
        left = 0
        right = len1
        while left <= right:
            i = int((left + right)/2)
            j = int((len1 + len2 + 1)/2) - i
            maxleft = minright = 0
            if i < len1 and j > 0 and nums1[i] < nums2[j-1]:
                left = i + 1
            elif i > 0 and j < len2 and nums1[i-1] > nums2[j]:
                right = i - 1
            else:
                if i == 0:
                    maxleft = nums2[j - 1]
                elif j == 0:
                    maxleft = nums1[i - 1]
                else:
                    maxleft = max(nums1[i - 1], nums2[j - 1])
                    if slen%2:
                        return maxleft
                    else:
                        if i == len1:minright = nums2[j]
                        elif j == len2:minright = nums1[i]
                        else:
                            minright = min(nums1[i], nums2[j])
                        return (left + minright)/2
        return 0.0

后续除非有python的简易实现,否则不给出Python代码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Leo木

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

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

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

打赏作者

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

抵扣说明:

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

余额充值