当前位置:   article > 正文

【Leetcode】347. 前 K 个高频元素_前k个高频元素 这个题什么意思

前k个高频元素 这个题什么意思

题目链接:347. Top K Frequent Elements

题目内容:给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

思路:就是统计每一个数字出现的次数,然后找到出现次数前k大的k个元素。统计数字出现的次数可以用哈希表。然后问题就转换成了求n个数中前k大的k个数

方法一:k个元素的小端堆

遍历数组nums,放入哈希表中,map<key,value>,key是数据,value是出现的次数。

将map中的key-value对放入数组中,构成一个二维数组entrys。

假设不同的数字一共有n个,entrys的长度就是n。就是求n个数中value最大的前k个数。

建立一个长度为k的小端堆,先用entrys中的前k个元素创建小端堆,堆顶元素是k个元素中value值最小的。然后依次遍历剩下的entrys[k]到entrys[n-1]。

如果遍历到的entrys[i]的value值小于堆顶元素的value,那么至少有k个元素的value比entrys[i]更大,不进行任何操作。如果大于堆顶元素的value,那么也说明至少有k个元素的value比堆顶元素的value大,那么就和堆顶元素进行交换,继续调整小端堆。

这样遍历完之后就能保证小端堆中的k个数value值就是最大的。得到了前k大的数。

js代码如下:

  1. var topKFrequent2 = function (nums, k) {
  2. // 堆排序
  3. function heapMinSort(nums, k) {
  4. function heapInsert(nums, i) {
  5. if (i == 0)
  6. return;
  7. let fi = Math.floor((i - 1) / 2);
  8. if (nums[i][1] >= nums[fi][1])
  9. return;
  10. else {
  11. let temp = nums[i];
  12. nums[i] = nums[fi];
  13. nums[fi] = temp;
  14. heapInsert(nums, fi);
  15. }
  16. }
  17. // 调整堆
  18. function heapify(nums, i, end) {
  19. let li = 2 * i + 1;
  20. let ri = 2 * i + 2;
  21. let index;
  22. if (li > end)
  23. return;
  24. else if (ri > end)
  25. index = li;
  26. else
  27. index = nums[li][1] < nums[ri][1] ? li : ri;
  28. if (nums[index][1] < nums[i][1]) {
  29. let temp = nums[index];
  30. nums[index] = nums[i];
  31. nums[i] = temp;
  32. heapify(nums, index, end);
  33. }
  34. }
  35. const length = nums.length;
  36. // 创建初始堆,只有k个元素的小端堆
  37. for (let i = 0; i < k; i++) {
  38. heapInsert(nums, i);
  39. }
  40. // 调整 保证前k个元素最大
  41. for (let i = k; i < length; i++) {
  42. if (nums[i][1] <= nums[0][1])
  43. continue;
  44. else {
  45. let temp = nums[0];
  46. nums[0] = nums[i];
  47. nums[i] = temp;
  48. heapify(nums, 0, k-1);
  49. }
  50. }
  51. }
  52. let map = new Map();
  53. const length = nums.length;
  54. // 哈希表是一定要用的O(n)
  55. for (let i = 0; i < length; i++) {
  56. if (map.has(nums[i]))
  57. map.set(nums[i], map.get(nums[i]) + 1);
  58. else
  59. map.set(nums[i], 1);
  60. }
  61. let entryArr = new Array();
  62. for (const entry of map) {
  63. entryArr.push(entry);
  64. }
  65. heapMinSort(entryArr, k);
  66. let resArr = new Array();
  67. for (let i = 0; i < k; i++) {
  68. resArr.push(entryArr[i][0]);
  69. }
  70. return resArr;
  71. };

其实也可以使用大端堆,创建长度为n的大端堆,排序时只排出k个,就得到了前k大的数。

方法二:快速排序

快速排序每一轮都能确定一个元素的最终位置,

假如对数组arr[0,n-1]进行从大到小排序,一个数据pivot的最终位置为p,那么arr[0,p-1]的元素都不小于arr[p],arr[p+1,n-1]的元素都不大于arr[p]。

判断k和p的大小:

如果k==p,那arr[0,p-1]就是前k大的元素。

如果k<p,那么再对arr[0,p-1]进行排序,找到k。

如果k>p,再对arr[p+1,n-2]进行排序,找到k。

这道题的思路和“第K大的元素”是类似的:

第K大的元素也可以使用快速排序(和本题思路一致),和堆排序(使用大端堆,大端堆排序的第k个元素就是第k大的元素。)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/677793
推荐阅读
相关标签
  

闽ICP备14008679号