4.寻找两个正序数组的中位数

杂谈:

        题目不难,最好想的当然是类似归并排序,也就是每次从nums1和nums2中拿一个更小的,直到某一个为空,或者找到了中间那个数(nums1.size()+nums2.size())/2

        这里主要记录一下官解给出的另外两种对数级的算法,主要是尝试用一个解题人的思想来理解算法

法一: 比较第k大,每次舍一半 O(log(m+n))

        我们取两个序列中第 k/2-1 大的元素,nums1的记为a,nums2的记为b,不妨设a<=b,又由于两个序列都是正序的,所以比a小的只可能是 nums1中0...k/2-2 和 nums2中0...k/2-2,这一共是 k/2-1 + k/2-1 <= k-2,也就是说a最大是第k-1大,也就说明a和它前面的那些元素都可以被舍弃.

        而当一个序列为空,直接返回另一个序列按序的指定元素即可, 因为我们每次舍弃k/2-1个,而当一个序列为空,就直接找到所求元素了,所以时间复杂度是O(log(m+n))

参考代码如下:

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        //法一: 归并排序 O(m+n)
        //法二: 删除小者的那一半log(m+n)
        //法三: m<n 对[0,m-1]做一个二分查找
        int m=nums1.size(),n=nums2.size();
        int k=(m+n+1)/2;//
        // 0...k/2-2,k/2-1...m-1   0...k/2-2,k/2-1...n-1
        // 所以对于nums1[k/2-1]和nums2[k/2-1]的小者,记为a
        //   至多只有 nums1的0...k/2-2 和 nums2的0...k/2-2 共 k/2-1 + k/2-1 <= k-2 个数,
        // 所以a至多是第k-1小,而中位数(第k小,前面一共k-1个数)也不会被误删
        auto ans=findKth(nums1,nums2,k,0,0);
        return (m+n)%2?ans.first:(ans.first+ans.second)*1.0/2;
    }
//我们直接同时取到 第k大 和 第k+1大
    pair<int,int> findKth(vector<int>& nums1,vector<int>& nums2,int k,int index1,int index2){
        if(index1>=nums1.size()){//nums1为空
            if(index2+k<nums2.size()){
                return {nums2[index2+k-1],nums2[index2+k]};
            }else{
                return {nums2[index2+k-1],INT_MAX};
            }
        }
        if(index2>=nums2.size()){//nums2为空
            if(index1+k<nums1.size()){
                return {nums1[index1+k-1],nums1[index1+k]};
            }else{
                return {nums1[index1+k-1],INT_MAX};
            }
        }
        if(k==1){// 12都非空,但是k=1了
            int first=INT_MAX,second=INT_MAX;
            if(nums1[index1]<=nums2[index2]){
                first=nums1[index1];
                second=nums2[index2];
                if(index1+1<nums1.size()) second=min(second,nums1[index1+1]);
            }else{
                first=nums2[index2];
                second=nums1[index1];
                if(index2+1<nums2.size()) second=min(second,nums2[index2+1]);
            }
            return {first,second};
        }
        int k1=k/2-1;
        int tmp1=INT_MAX,tmp2=INT_MAX;int cut1,cut2;//cut1 和 cut2是删除的个数
        if(index1+k1<nums1.size()){
            tmp1=min(tmp1,nums1[index1+k1]);
            cut1=k/2;
        }else{
            cut1=nums1.size()-index1;
        }
        if(index2+k1<nums2.size()){
            tmp2=min(tmp2,nums2[index2+k1]);
            cut2=k/2;
        }else{
            cut2=nums2.size()-index2;
        }
        if(tmp1<=tmp2){//比较这次选中的 两个元素
            return findKth(nums1,nums2,k-cut1,index1+cut1,index2);
        }else{
            return findKth(nums1,nums2,k-cut2,index1,index2+cut2);
        }
    }
};

法二: 根据中位数的定义

        我们找一个i,把nums1分成两部分, nums1[0...i-1](i个) 和 nums[i...m-1](m-i个),我们找一个j,同样把nums2分成两部分,nums2[0...j-1](j个) 和 nums[j...n-1](n-j个),如果能够使得前面(i+j) 个 和后面(m-i+n-j)个满足中位数的定义,就是了

        如果m+n是偶数,我们就找 i+j=m-i + n-j 同时使得

                                                nums1[i-1]<=nums[j] && nums2[j-1]<=nums1[i]​​​​​​​

        如果m+n是奇数,我们就找 i+j=m-i + n-j +1 同时使得

                                                nums1[i-1]<=nums[j] && nums2[j-1]<=nums1[i]

统一一下就是 i+j = (n+m+1)/2

那也就是找 i,j 使得 i+j = (n+m+1)/2 同时 nums1[i-1]<=nums[j] && nums2[j-1]<=nums1[i]

​​​​​​​这个命题等价于 寻找最大的 i 使得满足 i+j = (n+m+1)/2 同时 nums1[i-1]<=nums2[j], 简单证一下:

        首先说明存在, 随着i增大 nums1[i-1]增大 nums2[j]下降,所以会存在一个最大的i满足上式

        既然是最大的i那就说明,对i+1上式不成立,  也就是说(i+1) + (j-1) = (n+m+1)/2 而nums1[i] > nums2[j-1],也就是nums2[j-1]<nums1[i],甚至比原命题更强

        同时对于边界,我们取nums1[-1]=nums2[-1]=INT_MIN,nums1[n]=nums2[m]=INT_MAX,这样保障即使边界也是能正确取值的

        参考代码如下:

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        //法一: 归并排序 O(m+n)
        //法二: 删除小者的那一半log(m+n)
        //法三: m<n 对[0,m-1]做一个二分查找
        if(nums2.size()<nums1.size()){
            return findMedianSortedArrays(nums2,nums1);
        }//现在nums1是元素个数更少的了
        //0...i-1  |  i...m-1
        //0...j-1  |  j...n-1
        //i+j = n-i +m-j  ||  i+j = n-i +m-j+1 (或者左边多一个元素,所以是等于右边+1)  -> 
        //我们要求出来最大的i, 使得nums1[i-1]<nums2[j],nums2[j-1]<nums1[i]
        int m=nums1.size(),n=nums2.size();
        int l=0,r=nums1.size();
        int median1=INT_MIN,median2=INT_MIN;
        while(l<=r){
            int mid=(r-l)/2+l;
            int i=mid;int j=(m+n+1)/2-i;
            int nums1_i1=i==0?INT_MIN:nums1[i-1];
            int nums1_i =i==m?INT_MAX:nums1[i];
            int nums2_j1=j==0?INT_MIN:nums2[j-1];
            int nums2_j =j==n?INT_MAX:nums2[j];
            if(nums1_i1<=nums2_j){
                median1=max(nums1_i1,nums2_j1);
                median2=min(nums1_i, nums2_j);
                l=mid+1;
            }else{
                r=mid-1;
            }
        }
        return (m+n)%2?median1:(median1+median2)/2.0;
    }
};

  • 45
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com
寻找两个正序数组中位数可以使用归并的方式,合并两个有序数组,得到一个大的有序数组。然后找到大的有序数组的中间位置的元素,即为中位数。另一种方法是使用双指针的方式,维护两个指针,初始时分别指向两个数组的下标0的位置。每次将指向较小值的指针后移一位(如果一个指针已经到达数组末尾,则只需要移动另一个数组的指针),直到到达中位数的位置。这样可以在O(log(m+n))的时间复杂度内找到中位数。 具体步骤如下: 1. 初始化指针p1和p2分别指向两个数组的起始位置0。 2. 判断两个指针所指的元素大小,较小的元素所在的指针后移一位,直到其中一个指针到达数组末尾。 3. 若两个数组的长度之和为奇数,那么中位数即为当前指针指向的元素; 若两个数组的长度之和为偶数,那么中位数为当前指针指向的元素与其下一个元素的平均值。 4. 返回中位数作为结果。 需要注意的是,为了保证时间复杂度为O(log(m+n)),在每次移动指针时,应该移动的步数应该是当前指针所在数组长度的一半,即k/2,其中k为两个数组的长度之和。 以下是一个示例代码,用于说明上述方法的实现: ``` int findMedianSortedArrays(int[] nums1, int[] nums2) { int m = nums1.length; int n = nums2.length; int total = m + n; int middle = total / 2; int p1 = 0, p2 = 0; int prev = 0, curr = 0; for (int i = 0; i <= middle; i++) { prev = curr; if (p1 < m && (p2 >= n || nums1[p1 < nums2[p2])) { curr = nums1[p1++]; } else { curr = nums2[p2++]; } } if (total % 2 == 0) { return (prev + curr) / 2; } else { return curr; } } ``` 该方法可以在O(log(m+n))的时间复杂度内找到两个正序数组中位数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [算法:寻找两个正序数组中位数。](https://blog.csdn.net/en_joker/article/details/107179641)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [寻找两个正序数组中位数](https://blog.csdn.net/wulila/article/details/124483500)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值