ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

求两个有序数组的第K小数

2021-01-07 12:29:33  阅读:307  来源: 互联网

标签:数组 K1 vec2 arr2 有序 vec1 arr1 小数


题目

给定两个有序数组arr1和arr2,已知两个数组的长度分别为m1和m2,求两个数组中的第K小数。要求时间复杂度O(log(m1+ m2))。(题目和解题思路均来自《帅得玩编程》)

举例

eg1. arr1 = [1, 2, 3], arr2 = [3, 4, 5, 6], K = 4.
第K小数为3
eg2. arr1 = [0, 1, 2], arr2 = [3, 4, 5, 7, 8], K = 3.
第K小数为2

分析

该题其实是在两个长度相同的有序数组中找上中位数的扩展。扩展在以下2个方面:

  • 长度不同了(一个m1,另一个m2)
  • 不再是中位数(第K小数)
    这一题还是用递归解决,那么我们就来看看如何从“原问题”到“子问题”,换句话说,就是如何缩小问题的规模。

原问题—>子问题

找中位数那题中,利用中位数左右两边元素个数相等的特性,我们通过不断减少数组本身的长度来缩小问题的规模。但由于K的任意性,此法在本题中行不通。但是我们可以通过缩小“K”的值缩小问题的规模。我们以eg1为例讲解:
arr1 = [1, 2, 3]
arr2 = [3, 4, 5, 6]
K = 4

我们令K1 = K / 2(取整除),然后我们分别取出arr1arr2中第K1小的数arr1[K1 - 1]arr2[K1 - 1],进行对比,下面分情况讨论:

  • arr1[K1 - 1] >= arr2[K1 - 1],那么目标数肯定不在arr2 的前 K1个数里面。如此一来,我们就要在arr1[…]arr2[K1, …] 里面寻找第K - K1小的数
  • arr1[K1 - 1] < arr2[K1 - 1],同上理

有1个特殊情况,如果数组本身的元素个数小于取整除的结果,那么对于该数组而言,K1 就直接为该数组的长度。

代码

C++代码如下:

#include <iostream>
#include <vector>
#include <random>
#include <algorithm>
using namespace std;

typedef vector<unsigned short> Vec;
//K从1开始,返回第K大的数
unsigned short ret_kth(const Vec& vec1, const Vec& vec2, int K){
    int len1 = vec1.size(), len2 = vec2.size();
    //空数组情况
    if(len1 == 0 && len2 != 0){
        return vec2[K -1];
    }
    else if(len1 != 0 && len2 == 0){
        return vec1[K - 1];
    }
    else if(K == 1){
        //俩数组均不为空,且需要第1大的数,那么直接返回两数组的最小元素中的较小元素
        return vec1[0] < vec2[0] ? vec1[0] : vec2[0];
    }
    //在K大于1的情况下,先用第K/2大的数排除一部分元素
    int _K = K / 2; //_K < K
    //拿出每个数组的前_K个元素,比较两者中最大的两个数vec1[_K - 1]和vec2[_K - 1]的大小
    //其中较小的那个数及和与其在同一数组中且位于其之前的所有数都不可能为目标数
    //数组1中的第_K大的数,数组2中的第_K大的数
    unsigned short _Kth_1 = _K > len1 ? vec1.back() : vec1[_K - 1];
    int smaller_num1 = _K > len1 ? len1 : _K;  //数组1中可能被排除的元素个数
    unsigned short _Kth_2 = _K > len2 ? vec2.back() : vec2[_K - 1];
    int smaller_num2 = _K > len2 ? len2 : _K; //数组2中可能被排除的元素个数
    if(_Kth_1 <= _Kth_2){
        //排除数组1中的可能元素
        //构造不包含数组1前smaller_num1个元素的子数组
        Vec vec(vec1.begin() + smaller_num1, vec1.end());
        return ret_kth(vec, vec2, K - smaller_num1);
    }
    else{
        //排除数组2中的可能元素
        //....
        Vec vec(vec2.begin() + smaller_num2, vec2.end());
        return ret_kth(vec1, vec, K - smaller_num2);
    }

    return 0;
}
//重载输出流,用于打印数组
ostream& operator<<(ostream& out, const Vec& v){
    for(auto num : v){
        out << num << "  ";
    }
    out << endl;
    return out;
}

// 测试用例
int main(){
    uniform_int_distribution<unsigned short> u(0, 1000);
    default_random_engine e;

    //数组1
    Vec vec1;
    for(int i = 0; i < 10; ++i){
        vec1.push_back(u(e));
    }
    cout << "数组1:";
    sort(vec1.begin(), vec1.end());
    cout << vec1;
    //数组2
    Vec vec2;
    for(int i = 0; i < 0; ++i){
        vec2.push_back(u(e));
    }
    cout << "数组2:";
    sort(vec2.begin(), vec2.end());
    cout << vec2;
    //合并
    cout << "合并之后的数组:";
    Vec joint_vec;
    joint_vec.insert(joint_vec.end(), vec1.begin(), vec1.end());
    joint_vec.insert(joint_vec.end(), vec2.begin(), vec2.end());
    sort(joint_vec.begin(), joint_vec.end());
    cout << joint_vec;
    //返回第K个数
    unsigned short Kth = ret_kth(vec1, vec2, 9);
    cout << Kth << endl;

    return 0;
}

标签:数组,K1,vec2,arr2,有序,vec1,arr1,小数
来源: https://blog.csdn.net/weixin_38165206/article/details/112243862

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有