Leetcode:4. 两个排序数组的中位数

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 

请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。

你可以假设 nums1 和 nums2 不同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

中位数是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

中位数是 (2 + 3)/2 = 2.5

解题思路:

二分法,求第K大的数。当两个数组总个数为奇数时,中位数是第K=(nums1.size()+nums2.size()+1)/2 大的数;当两个数组总个数为偶数时,需要第K大的数与第K+1大的数二者取平均,其中K=(nums1.size()+nums2.size())/2,于是算法的核心就转换成如何求解第K大的数,时间复杂度为log(n+m)。通过程序流程可以很容易得理解算法的主要思想。

例子nums1=[1,2,3,4,5,6,7,8,9,10];

nums2=[3,4,6,7,11,12];

求解第K=7大的数,K<=nums1.size()+nums2.size()=16。

1. 根据K值缩小查找范围。取两个数组的前K个,如果当前数组不够那就全取。此刻nums1=[1,2,3,4,5,6,7];nums2=[3,4,6,7,11,12];这样一来第K=7大的数就必然在这之间。

2. 为了方便处理,通常设置nums1的长度大,如果不是那就交换nums1,nums2;

3. nums1的长度可能不足K个,需要填充最大值来确保nums1的长度为K,此刻并不影响第K大的数,只是为了方便处理。

4. 在确保nums1的长度为K之后,将pos1=k-2=5,nums1[pos1]=6;pos2=0,nums[pos2]=3;此刻我们选取了K个数。

5.我们发现3后面的数小于6,所以pos1,pos2不是最终位置,因此需要迭代,理论上pos2(更小的那个)一直往后加一,同时pos1(更大的那个)往前减一,就必然能找到那个结果,但是时间复杂度为m+n。

6. 利用二分。其实每一次的移动量为1是不必要的,应该设置为可移动区间的中间位置,区间为闭区间[left,right]。

7.初始时刻pos1的访问区间,board_max=[0,pos1],board_min=[pos2,nums2.size()-1]。

8. pos2往后移动move = (board.right-board.left)/2 = 2。与此同时,pos1往前移动move。修改区间,borad_max=[left,right-move]=[0,3],board_min=[left+move,right]=[2,5]。

9. 查看当前位置是否需要换边。nums1[3]=4,nums2[2]=6。这个时候,更大的数值和更小的数值换了边,之前第4步,更大在nums1,而现在到了nums2。有换边情况也是需要修改移动区间,因为他们的移动方向会发生改变,这是本次刷题遇到的主要错误。board_max=[right-move,pre_max]=[3,5];board_min=[pre_min,left+move];swap(board_max,board_min);其中pre_max是指针往前移动之前的位置,pre_min是指针往后移动之前的位置!!!

10. 考虑移动区间的边界之后,再次考虑迭代条件。这个时候访问到nums1[3]=4,nums2[2]=6,4后面的数值为5<6所以迭代。迭代条件是更小的数后面一个数小于更大的那个数。移动量move=1。访问nums1[4]=5,nums2[1]=4。此刻又发生了换边,但是不满足迭代条件,因为4后面的数6<5。此刻return max=5即可。

11. 解决了查找第K个数的问题之后查找中位数简直so easy!

111

C++代码
class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int size1 = nums1.size(), size2 = nums2.size();
        if (size1 == 0) {
            if (size2 % 2 == 1) return nums2[size2 / 2];
            else return double(nums2[size2 / 2 - 1] + nums2[size2 / 2]) / 2;
        }
        else if (size2 == 0) {
            if (size1 % 2 == 1) return nums1[size1 / 2];
            else return double(nums1[size1 / 2 - 1] + nums1[size1 / 2]) / 2;
        }
        else {
            if ((size1 + size2) % 2 == 1) return findKth(nums1, nums2, (size1 + size2 + 1) / 2);
            else return (findKth(nums1, nums2, (size1 + size2) / 2 ) + findKth(nums1, nums2, (size1 + size2) / 2+1)) / 2;
        }
    }
    double findKth(vector<int> nums1, vector<int> nums2, int k) {//在两个数组中找第k大的数,数组已排序。
        if (nums1.size() < nums2.size()) swap(nums1, nums2);
        vector<int>::iterator it_max; 
        vector<int>::iterator it_min;
        int size1 = nums1.size(), size2 = nums2.size();
        int max = (nums1[size1 - 1] > nums2[size2 - 1] ? nums1[size1 - 1] : nums2[size2 - 1]);
        if (int(nums1.size()) <= k) { int n = k - int(nums1.size()); while (n--) { nums1.push_back(max); size1++; } }
        if (int(nums2.size() <= k)&& int(nums1.size())>k) { nums1.erase(nums1.begin() + k, nums1.end());}
        else {
            if (int(nums1.size()) > k) nums1.erase(nums1.begin() + k, nums1.end());
            if (int(nums2.size()) > k) nums2.erase(nums2.begin() + k, nums2.end());
        }
        if (nums1[k - 2] == nums2[0]) return nums1[k - 2];
        int pos_max, pos_min, max_size, min_size;
        if (nums1[k - 2] > nums2[0]) {
            it_max = nums1.begin();
            it_min = nums2.begin();
            pos_max = k - 2;
            pos_min = 0;
            max_size = nums1.size();
            min_size = size2;
        }
        else {
            it_max = nums2.begin();
            it_min = nums1.begin();
            pos_max = 0;
            pos_min = k - 2;
            max_size = size2;
            min_size = nums1.size();
        }
        pair<int, int> board_max(0, pos_max), board_min(pos_min, min_size - 1);
        int sgn1, move, pre_min, pre_max;
        while ((pos_min<board_min.second&&pos_min>=board_min.first)&&it_min[pos_min + 1] < it_max[pos_max]) {//迭代条件
            sgn1 = board_min.second - pos_min;
            move = (sgn1 % 2 == 0 ? sgn1 / 2 : sgn1 / 2 + 1);
            pre_min = pos_min; pre_max = pos_max;
            pos_min = pos_min + move;
            board_min.first = pos_min;
            pos_max = pos_max - move;
            board_max.second = pos_max;
            //检测是否有必要交换指针
            if (pos_max<0||(pos_max>=0&&it_max[pos_max] < it_min[pos_min])) { 
                swap(it_max, it_min); 
                swap(pos_max, pos_min); 
                swap(max_size, min_size);
                swap(board_min, board_max);
                board_min.first = board_min.second;
                board_min.second = pre_max;
                board_max.second = board_max.first;
                board_max.first = pre_min;
            }
        }
        return it_max[pos_max];
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip
毕设新项目基于python3.7+django+sqlite开发的学生就业管理系统源码+使用说明(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 学生就业管理系统(前端) ## 项目开发环境 - IDE: vscode - node版本: v12.14.1 - npm版本: 6.13.4 - vue版本: @vue/cli 4.1.2 - 操作系统: UOS 20 ## 1.进入项目目录安装依赖 ``` npm install ``` ## 2.命令行执行进入UI界面进行项目管理 ``` vue ui ``` ## 3.编译发布包(请注意编译后存储路径) #### PS:需要将编译后的包复制到后端项目的根目录下并命名为'static' 学生就业管理系统(后端) ## 1.项目开发环境 - IDE: vscode - Django版本: 3.0.3 - Python版本: python3.7.3 - 数据库 : sqlite3(测试专用) - 操作系统 : UOS 20 ## 2.csdn下载本项目并生成/安装依赖 ``` pip freeze > requirements.txt pip install -r requirements.txt ``` ## 3.项目MySQL数据库链接错误 [点击查看解决方法](https://www.cnblogs.com/izbw/p/11279237.html)
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值