首页 > 其他分享 >4. 寻找两个正序数组的中位数

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

时间:2024-11-15 20:46:59浏览次数:1  
标签:正序 int 中位数 L2 数组 L1 nums1 nums2 mid1

  1. 题目链接

  2. 解题思路

    • 用双指针,或者辅助数组的方法这里就不过多解释了,现在说最优解。
    • 我们可以利用两个数组「有序」的特点,找到其中位数。
    • 直接举例子,假设其中一个数组nums1是[1, 3, 5, 7, 9],另一个数组nums2是[2, 4, 6, 8],中位数我们先人工算出来,是5,也就是整体的第5小的数,也就是说,我们目的就是找整体第5小的数。
      • 先在nums1中取中位数, 5,然后在nums2中,找到小于等于5,最右侧的位置,就是4,然后我们可以计算,nums2中,2, 4是两个数,nums1中1,3,5是三个数,然后,这5个数,正好等于我们要找到第5小的数,所以直接返回5了。
    • 可能还有些抽象,其实思路很简单,就是第一个数组,在[L1, R1]上,第二个数组[L2, R2]上,求第k小。我首先得到mid = (R1+L1)/2,然后在nums2中找到小于等于nums1[mid]最右侧的位置,假设是x,那么我们就可以知道nums1中,一共有mid - L1 + 1个数,nums2中,一共有x - L2 + 1个数,一共y个数,
      • 如果k == y,那么我们可以直接返回nums1[mid]
      • 如果k < y,那么我们可以在[L1, mid]以及[L2, x]中,继续找第k小的数
      • 如果k > y,那么我们可以在[mid + 1, R1] 以及[x + 1, R2]中,继续找第y - k小的数
    • 还有点懵?看代码,边看边理解。
    • 感性地感觉,每次能淘汰一半长度的数。而在「nums2中找到小于等于nums1[mid]最右侧的位置」,可以使用二分法找,所以时间复杂度是O(log(n + m))
  3. 代码

    
    class Solution {
    public:
        // 在nums1[L1, R1]和nums2[L2, R2]上,找到第k小的数
        int process(vector<int> &nums1, vector<int> &nums2, int L1, int R1, int L2, int R2, int k) {
            if (L1 > R1) {   // nums1没有数了 也就是说  直接找到nums2第k小的数即可
                return nums2[L2 + k - 1];
            }
            int mid1 = (R1 + L1) / 2;
            int i = L2;
            int j = R2;
            int index = -1;
            // 在nums2[L2, R2]中,找到小于等于nums1[mid1]的最右的位置
            while(i <= j) {
                int mid = (i + j) / 2;
                if (nums1[mid1] >= nums2[mid]) {
                    index = mid;
                    i = mid + 1;
                }else {
                    j = mid - 1;
                }
            }
            if (index == -1) {    // 没有找到,也就是说nums2[L2, R2]所有的数,都大于nums1[mid1]
                if (mid1 - L1 + 1 > k) {
                    return nums1[L1 + k - 1];
                } else if(mid1 - L1 + 1 == k) {
                    return nums1[mid1];
                } else {
                    return process(nums1, nums2, mid1 + 1, R1, L2, R2, k - mid1 + L1 - 1);
                }
            } else {   // 找到了
                if (mid1 - L1 + 1 + index - L2 + 1 > k) {
                    // 注意 变成了nums1[L1, mid1-1] 和nums2[L2, index]
                    // 因为nums1[mid1]是 nums1[L1, mid1] 和nums2[L2, index]最大的数  mid1可以被淘汰了
                    // 并且,如果不是mid1 - 1,这里可能进入死递归
                    return process(nums1, nums2, L1, mid1 - 1, L2, index, k);
                } else if(mid1 - L1 + 1 + index - L2 + 1 == k) {
                    return nums1[mid1];
                } else {
                    return process(nums1, nums2, mid1 + 1, R1, index + 1, R2, k - mid1 + L1 - 2 - index + L2);
                }
            }
        }
    
    
        double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
            int n = nums1.size();
            int m = nums2.size();
            if ((n + m) % 2 == 0) {   // 长度和是偶数  要找两个
                double ans1 = process(nums1, nums2, 0, n - 1, 0, m - 1, (n + m) / 2);
                double ans2 = process(nums1, nums2, 0, n - 1, 0, m - 1, (n + m) / 2 + 1);
                return (ans1 + ans2) / 2;
            } else {    // 长度和是奇数   找一个
                return process(nums1, nums2, 0, n - 1, 0, m - 1, (n + m) / 2 + 1);
            }
        }
    };
    

标签:正序,int,中位数,L2,数组,L1,nums1,nums2,mid1
From: https://www.cnblogs.com/ouyangxx/p/18548636

相关文章

  • 数组...
    2.1.1什么是数组,为什么要使用数组?java中存储数据的最小单元是变量,一个变量只能存储一个数据,如果需要存储大量的数据就需要使用大量的变量,因此需要一种新的数据类型能够存储大量数据的数据类型-数组数组-用来存储大量相同数据的集合。2.1.2如何使用数组?1)数组的初始化数据......
  • JavaScript常用对象方法二:数组(array)
    1.concat()用于连接两个或多个数组。该方法不会改变现有的数组,而是返回一个新的数组。个人感觉es6出来的扩展运算符比这个方法要简洁一些扩展运算符的方法:constarr1=[1,2];constarr2=[3,4];constarr3=[...arr1,...arr2];console.log(arr3);//[1,2,......
  • 旋转数组的最小数字
    题目把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{2,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1.解题思路看到“递增数组”和“查找最小值”,就要想到二分法。有两种切割方法,一......
  • leetcode 数组专题 06-扫描线算法(Sweep Line Algorithm)
    扫描线专题leetcode数组专题06-扫描线算法(SweepLineAlgorithm)leetcode数组专题06-leetcode.218the-skyline-problem力扣.218天际线问题leetcode数组专题06-leetcode.252meetingroom力扣.252会议室leetcode数组专题06-leetcode.253meetingroomii力扣.253......
  • C语言:数组(一维数组,二维数组,数组越界,数组作为函数参量,冒泡排序)
    1、一维数组的创建和初始化1.1、数组的创建数组是相同类型元素的集合•数组中可以存放1个或者多个数据•数组中存放的数据,类型是相同的数组的创建方式:元素类型自定义数组名(常量表达式)比如:intarr[10]doublearr[5]chararr[8+5]错误写法:intarr[n];......
  • 代码随想录:有序数组的平方
    代码随想录:有序数组的平方仍然是双指针,一开始也想到了双指针,不过很笨的创造了两个数组,一个负数的一个正数的,两个数组比大小后插入。但其实可以直接把原数组平方后,从左右两边插入。有两点值得注意:1.已知数组大小的情况下,可以直接倒着插入数组。2.创建vector时需要指定元素的个数......
  • 郝玩的数据结构2——树状数组(待upd)
    首先,拉张图树状数组,相对于线段树来说,空间复杂度更小,但是可以处理的信息具有局限性常用于处理区间(矩阵)查改(差分转化为单点查改),单点查改板子题1Accode:点击查看代码#include<bits/stdc++.h>#definelowbitx&-xusingnamespacestd;intn,m,s[500005];voidchange(intx......
  • Java 数组操作:反转、扩容与缩容
    在Java中,数组是一种固定长度的数据结构,一旦创建,其大小无法更改。然而,常常在实际编程中,我们需要对数组进行扩容、缩容或其他操作。本文将介绍如何通过Java实现数组反转、扩容和缩容的操作,并在代码中演示这些常见的数组操作。1.数组反转数组反转是一个常见的操作,通常用于......
  • 代码随想录算法训练营第一天| 704. 二分查找、35.搜索插入位置、27. 移除元素、977.有
    文档讲解:代码随想录视频讲解:代码随想录状态:完成4道题一、数组理论基础数组:连续内存空间,存储类型相同的元素集合,适合读不适合写注意:Python里可以存储不同类型的元素,但刷题时都是按照相同元素去做的相同元素占用存储的空间大小是一样的,下一个元素的位置就确定了数组时间......
  • 代码随想录算法训练营第二天| 209.长度最小的子数组、59. 螺旋矩阵 II
    文档讲解:代码随想录视频讲解:代码随想录状态:完成2道题滑动窗口滑动窗口:两个指针一前一后组成滑动窗口,并计算滑动窗口中的元素的问题适用场景:字符串匹配问题、子数组问题、定长问题滑动窗口模板:如果一个字符进入窗口,应该增加windows计数器;如果一个字符将移除窗口的......