/** * @param {number[]} nums * @param {number} k * @return {number[]} */var topKFrequent = function (nums, k) { let map = new Map(); // 用Map记录所有数字出现的频率
// 遍历数组,记录每个数字的出现频率,将其保存在Map中 for (let i = 0; i < nums.length; i++) { if (map.has(nums[i])) { map.set(nums[i], map.get(nums[i]) + 1); } else { map.set(nums[i], 1); } }
// 将数字和频率的关系转换成数组,用于排序。 const numsWithFrequency = [...map.entries()];
// 使用快速排序,将数组按频率从大到小排序,并返回前k个数字 return quickSort(numsWithFrequency, 0, numsWithFrequency.length - 1, k);};
const quickSort = (nums, left, right, k) => { // 如果nums的长度小等于1,无需排序,直接将数字取出返回 if (nums.length <= 1) return nums.map(([num]) => num);
// 如果nums有长度,就需要排序 if (left < right) { // 将nums从left到right的部分分为两段,其中间值是pivot // pivot左侧的值都小于nums[pivot],pivot右侧的值都大于nums[pivot] const pivot = partition(nums, left, right);
// 如果pivot刚好等于k,表示排序提前完成,可以直接返回结果 if (pivot === k) { // 将前k个元素转换为数字返回 return nums.slice(0, k).map(([num]) => num); }
// 按pivot将nums拆分成两端分别排序,由于该题并未要求将数组完全排序,因此只需要将前k个元素整理到一侧即可 // 由于我们事先不知道pivot与k的大小关系,因此需要根据k的位置进行递归 pivot > k ? quickSort(nums, left, pivot - 1, k) : quickSort(nums, pivot + 1, right, k); }
// 完成排序后,将前k个元素转换为数字返回即可 return nums.slice(0, k).map(([num]) => num);};
const partition = (nums, left, right) => { let pivot = left; // 以left为中值,比它大的都放在其左侧,比它大的都放在其右侧 let index = left + 1; // 从left+1开始遍历数组,同时index表示了频率比nums[pivot]大的值存放的位置
// 遍历从left+1到right的元素,将其以nums[pivot]为中值拆分成两半 for (let i = index; i <= right; i++) { // 如果当前频率比nums[pivot]大,则将其移动到index的位置 if (nums[i][1] > nums[pivot][1]) { // 将nums[i]与nums[index]对调 [nums[i], nums[index]] = [nums[index], nums[i]]; // 将index移动一位,用于存储下一个值 index++; } }
// 完成循环时,index多移动了一位,要将其回退 index--; // 循环停止时,index位置存储的是频率大于nums[pivot]的值,而nums[pivot]还在原地 // 将两者对调,中值会被移动到index的位置,在其左侧的频率都比它大 [nums[pivot], nums[index]] = [nums[index], nums[pivot]];
// 将新的中值返回,下层递归根据它将数组拆分成两段继续排序 return index;};
评论