前言
一、BM47 寻找第K大
题目描述
描述:
有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。
给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在
要求:时间复杂度 O(nlogn),空间复杂度O(1)
数据范围:0≤n≤1000, 1≤K≤n,数组中每个元素满足 0≤val≤10000000
示例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; } } }