今天给大家分享一下每日刷题的题目解析和经验分享,本系列预计会推出五期,今天给大家带来的是第三期的分享。
视频推荐的算法
问题描述
西瓜视频正在开发一个新功能,旨在将访问量达到80百分位数以上的视频展示在首页的推荐列表中。实现一个程序,计算给定数据中的80百分位数。
例如:假设有一个包含从1到100的整数数组,80百分位数的值为80,因为按升序排列后,第80%位置的数字就是80。
99 百分位数:假如有 N 个数据,将数据从小到大排列,99 百分位数是第 N99%位置处的数据(遇到小数时四舍五入获取整数)。一般计算逻辑是先排序,定位到 N99%的位置。返回该位置处的数据。同理,80 百分位数就是第 N*80%位置处的数据。
测试样例
样例1:
输入:
data = "10,1,9,2,8,3,7,4,6,5"
输出:8
样例2:
输入:
data = "1,0,8,7,3,9,12,6,4,15,17,2,14,5,10,11,19,13,16,18"
输出:15
样例3:
输入:
data = "5,3,9,1,7"
输出:7
解决方案
要解决这个问题,我们需要计算给定数据中的80百分位数。
-
理解百分位数:
- 百分位数是指在一个数据集中,某个百分比位置的数值。例如,80百分位数是指在排序后的数据中,80%位置的数值。
- 具体来说,如果数据集有N个元素,80百分位数就是第
N * 0.8位置的元素。如果N * 0.8不是整数,则需要四舍五入到最近的整数。
-
数据处理:
- 输入数据是一个字符串,表示一组数字,数字之间用逗号分隔。
- 首先需要将字符串解析为整数数组。
-
排序:
- 将解析后的整数数组按升序排序。
-
计算位置:
- 计算80百分位数的位置:
int position = (int) Math.round(data.length * 0.8); - 注意:数组索引从0开始,所以实际的索引位置是
position - 1。
- 计算80百分位数的位置:
-
返回结果:
- 返回排序后数组中对应位置的数值。
public class Main {
public static int solution(String data) {
// 1. 将输入的字符串解析为整数数组
String[] parts = data.split(",");
int[] numbers = new int[parts.length];
for (int i = 0; i < parts.length; i++) {
numbers[i] = Integer.parseInt(parts[i]);
}
// 2. 对整数数组进行排序
Arrays.sort(numbers);
// 3. 计算80百分位数的位置
int position = (int) Math.round(numbers.length * 0.8);
// 4. 返回排序后数组中对应位置的数值
// 注意:数组索引从0开始,所以实际的索引位置是 position - 1
return numbers[position - 1];
}
public static void main(String[] args) {
// 测试代码如下
System.out.println(solution("10,1,9,2,8,3,7,4,6,5") == 8);
System.out.println(solution("1,0,8,7,3,9,12,6,4,15,17,2,14,5,10,11,19,13,16,18") == 15);
System.out.println(solution("76,100,5,99,16,45,18,3,81,65,102,98,36,4,2,7,22,66,112,97,68,82,37,90,61,73,107,104,79,14,52,83,27,35,93,21,118,120,33,6,19,85,49,44,69,53,67,110,47,91,17,55,80,78,119,15,11,70,103,32,9,40,114,26,25,87,74,1,30,54,38,50,8,34,28,20,24,105,106,31,92,59,116,42,111,57,95,115,96,108,10,89,23,62,29,109,56,58,63,41,77,84,64,75,72,117,101,60,48,94,46,39,43,88,12,113,13,51,86,71") == 96);
}
}
复杂度分析
时间复杂度
-
解析字符串并转换为整数数组:
data.split(","):分割字符串的时间复杂度为 O(n),其中 n 是字符串的长度。Integer.parseInt(parts[i]):遍历字符串数组并转换为整数的时间复杂度为 O(m),其中 m 是数组的长度。- 因此,这一步的总时间复杂度为 O(n + m)。
-
排序整数数组:
Arrays.sort(numbers):Java 的Arrays.sort()方法使用的是优化的快速排序或归并排序,平均时间复杂度为 O(m log m)。
-
计算80百分位数的位置:
Math.round(numbers.length * 0.8):计算位置的时间复杂度为 O(1)。
-
返回结果:
return numbers[position - 1]:访问数组元素的时间复杂度为 O(1)。
综合以上步骤,主要的时间复杂度来自于排序操作,因此总的时间复杂度为 。
空间复杂度
-
解析字符串并转换为整数数组:
String[] parts = data.split(","):需要额外的空间存储分割后的字符串数组,空间复杂度为 O(m)。int[] numbers = new int[parts.length]:需要额外的空间存储整数数组,空间复杂度为 O(m)。
-
排序整数数组:
Arrays.sort(numbers):排序操作本身不需要额外的空间,但快速排序或归并排序可能会使用一些辅助空间,最坏情况下为 O(m)。
-
计算80百分位数的位置:
Math.round(numbers.length * 0.8):计算位置不需要额外的空间,空间复杂度为 O(1)。
-
返回结果:
return numbers[position - 1]:访问数组元素不需要额外的空间,空间复杂度为 O(1)。
综合以上步骤,主要的空间复杂度来自于存储整数数组和分割后的字符串数组,因此总的空间复杂度为 O(m)。
总结
- 时间复杂度:O(mlogm)
- 空间复杂度:O(m)
其中,m 是输入字符串中数字的数量。