【牛客面试必刷TOP101】Day27.(X)BM47 寻找第K大和BM48 数据流中的中位数

文章目录

  • 前言
  • 一、BM47 寻找第K大
  • 题目描述
  • 题目解析
  • 二、BM48 数据流中的中位数
  • 题目描述
  • 题目解析
  • 总结


前言


一、BM47 寻找第K大

题目描述

描述:

有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。

给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在


要求:时间复杂度 O(nlogn),空间复杂度O(1)

数据范围:0≤n≤1000, 1≤K≤n,数组中每个元素满足 0≤val≤10000000


示例1:


示例2:


题目解析


二、BM48 数据流中的中位数

题目描述

描述:

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。


数据范围:数据流中数个数满足 1≤n≤1000  ,大小满足 1≤val≤1000 
进阶: 空间复杂度 O(n), 时间复杂度 O(nlogn)


示例1:


示例2:


题目解析

方法一:插入排序法(推荐使用)

知识点:插入排序

插入排序是排序中的一种方式,一旦一个无序数组开始排序,它前面部分就是已经排好的有序数组(一开始长度为0),而其后半部分则是需要排序的无序数组,插入排序的做法就是遍历后续需要排序的无序部分,对于每个元素,插入到前半部分有序数组中属于它的位置——即最后一个小于它的元素后。

思路:

传统的寻找中位数的方法便是排序之后,取中间值或者中间两位的平均即可。但是这道题因为数组在不断增长,每增长一位便需要排一次,很浪费时间,于是可以考虑在增加数据的同时将其有序化,这个过程就让我们想到了插入排序:对于每个输入的元素,遍历已经有序的数组,将其插入到属于它的位置。

int i = 0;
//遍历找到插入点
for(; i < val.size(); i++){
    if(num <= val.get(i))
        break;
}
//插入相应位置
val.add(i, num);

具体做法:

  • step 1:用一数组存储输入的数据流。
  • step 2:Insert函数在插入的同时,遍历之前存储在数组中的数据,按照递增顺序依次插入,如此一来,加入的数据流便是有序的。
  • step 3:GetMedian函数可以根据下标直接访问中位数,分为数组为奇数个元素和偶数个元素两种情况。记得需要类型转换为double。

代码实现流程:

  • 首先定义一个ArrayList val,用于存储插入的数字。
  • 定义一个Insert函数,用于插入数字。该函数接收一个整数num作为参数。
  • 首先判断val是否为空,如果为空,则直接将num添加到val中。
  • 如果val不为空,则需要进行插入排序。
  • 定义一个变量i,初始值为0,用于记录插入的位置。
  • 使用for循环遍历val,找到第一个大于等于num的位置,即插入点。
  • 将num插入到插入点的位置,使用val.add(i, num)。
  • 定义一个GetMedian函数,用于获取中位数。
  • 首先获取val的长度n。
  • 如果n是奇数,则中位数是val的第(n/2)个元素,直接返回该值。
  • 如果n是偶数,则中位数是val的第(n/2)个元素和第(n/2-1)个元素的平均值,将两个元素取出并求平均值,返回该值。

代码解析:

import java.util.*;
public class Solution {
    //1.首先定义一个ArrayList val,用于存储插入的数字
    private ArrayList<Integer> val = new ArrayList<Integer>();
    public void Insert(Integer num) {
        //2.首先判断val是否为空,如果为空,则直接将num添加到val中。
        if (val.isEmpty())
            //val中没有数据,直接加入
            val.add(num);
        //3.如果val不为空,则需要进行插入排序。
        else {
            //定义一个变量i,初始值为0,用于记录插入的位置。
            int i = 0;
            //使用for循环遍历val,找到第一个大于等于num的位置,即插入点。
            for (; i < val.size(); i++) {
                if (num <= val.get(i))
                    break;
            }
            //将num插入到插入点的位置,使用val.add(i, num)。
            val.add(i, num);
        }
    }

    public Double GetMedian() {
        //1.首先获取val的长度n。
        int n = val.size();
        //(1)如果n是奇数,则中位数是val的第(n/2)个元素,直接返回该值。
        
        if (n % 2 == 1)
            //类型转换
            return (double)val.get(n / 2);
        //(2)如果n是偶数,则中位数是val的第(n/2)个元素和第(n/2-1)个元素的平均值,将两个元素取出并求平均值,返回该值。
        else {
            double a = val.get(n / 2);
            double b = val.get(n / 2 - 1);
            return (a + b) / 2;
        }
    }
}

总结

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值