你好,欢迎来到潮汕IT智库!
您的位置:首页 > IT资讯> 热点新闻 热点新闻
Top N 的算法题如何解决
2024-07-18 10:07:43 作者: (评论0条)

解决Top N(前N大或前N小)的算法问题通常涉及到对数据进行排序、筛选或堆的操作。以下是一些常见的解决方法:

1、 排序法

对整个数据集进行排序,然后取出前N个元素作为结果。时间复杂度为O(nlogn),适用于数据量不大的情况。

2、 部分排序法

可以使用部分排序算法,比如堆排序中的堆,只维护前N个最大或最小元素。时间复杂度为O(nlogN),适用于大数据集合。

3、 计数法

对数据进行计数,并选择出前N个最大或最小的元素。适用于数据有一定范围的情况。

4、 分治法

使用分治法,将数据分割成不同的部分,只处理包含前N个元素的部分。适用于数据量大且分布均匀的情况。

5、 优先队列(堆): 使用堆数据结构来维护前N个元素,可以实现较高效的Top N查找。时间复杂度为O(nlogN)。

6、 快速选择算法

类似于快速排序的思想,通过每次选择一个基准值,将数据分为比基准值大和小的两部分,只处理包含前N个元素的部分。时间复杂度为O(n)。

根据具体情况选择合适的算法,通常在处理大数据集时,优先考虑堆排序或快速选择算法,因为它们可以在较短的时间内找到Top N元素

部分排序

function findTopN(arr, n) {    // 部分排序法    for (let i = 0; i < n; i++) {        for (let j = i + 1; j < arr.length; j++) {            if (arr[j] > arr[i]) {                [arr[i], arr[j]] = [arr[j], arr[i]];            }        }    }
   return arr.slice(0, n);}
// 示例const arr = [3, 10, 4, 7, 6, 9, 1];const n = 3;const topN = findTopN(arr, n);console.log(`前${n}个最大值为:${topN}`);

计数法

function findTopN(arr, n) {    // 计数法    const counts = {};    arr.forEach(num => {        counts[num] = (counts[num] || 0) + 1;    });
   const uniqueNums = Object.keys(counts).map(Number);    uniqueNums.sort((a, b) => b - a); // 降序排序
   const result = [];    let count = 0;    for (let num of uniqueNums) {        const freq = counts[num];        for (let i = 0; i < freq && count < n; i++) {            result.push(num);            count++;        }        if (count >= n) {            break;        }    }
   return result;}
// 示例const arr = [3, 10, 4, 7, 6, 9, 1, 10, 10, 7];const n = 3;const topN = findTopN(arr, n);console.log(`前${n}个最大值为:${topN}`);

分治法

function findTopN(arr, n) {  // 分治法  function quickSelect(arr, k, left, right) {      if (left === right) {          return arr[left];      }
     let pivotIndex = Math.floor(Math.random() * (right - left + 1)) + left;      pivotIndex = partition(arr, left, right, pivotIndex);
     if (k === pivotIndex) {          return arr[k];      } else if (k < pivotIndex) {          return quickSelect(arr, k, left, pivotIndex - 1);      } else {          return quickSelect(arr, k, pivotIndex + 1, right);      }  }
 function partition(arr, left, right, pivotIndex) {      let pivotValue = arr[pivotIndex];      [arr[pivotIndex], arr[right]] = [arr[right], arr[pivotIndex]];      let storeIndex = left;
     for (let i = left; i < right; i++) {          if (arr[i] > pivotValue) {              [arr[i], arr[storeIndex]] = [arr[storeIndex], arr[i]];              storeIndex++;          }      }
     [arr[storeIndex], arr[right]] = [arr[right], arr[storeIndex]];      return storeIndex;  }
 const result = [];  for (let i = 0; i < n; i++) {      result.push(quickSelect(arr, i, 0, arr.length - 1));  }
 return result;}
// 示例const arr = [3, 10, 4, 7, 6, 9, 1];const n = 3;const topN = findTopN(arr, n);console.log(`前${n}个最大值为:${topN}`);

快速选择算法

快速选择算法(Quickselect)它是快速排序的一种变体。要找到前N个最大的元素,我们可以利用快速选择算法找到第k大的元素,然后对前k大的元素进行筛选。

function partition(arr, left, right) {  let pivot = arr[right];  let i = left;  for (let j = left; j < right; j++) {      if (arr[j] >= pivot) {  // 注意这里是 >= ,因为我们要找的是前N个最大的元素          [arr[i], arr[j]] = [arr[j], arr[i]];          i++;      }  }  [arr[i], arr[right]] = [arr[right], arr[i]];  return i;}
function quickselect(arr, left, right, k) {  if (left <= right) {      let pivotIndex = partition(arr, left, right);      if (pivotIndex === k) {          return arr.slice(0, k + 1);      } else if (pivotIndex < k) {          return quickselect(arr, pivotIndex + 1, right, k);      } else {          return quickselect(arr, left, pivotIndex - 1, k);      }  }  return [];}
function findTopNElements(arr, n) {  if (n <= 0) {      return [];  }  if (n >= arr.length) {      return arr.slice().sort((a, b) => b - a);  }  return quickselect(arr, 0, arr.length - 1, n - 1);}
// 示例用法const arr = [3, 2, 1, 5, 6, 4];const n = 3;const topNElements = findTopNElements(arr, n);console.log(`前${n}个最大的元素:`, topNElements);


1、partition函数:这个函数用于将数组分成两部分,以选择的枢轴为基准,将大于等于枢轴的元素放在左边,小于枢轴的元素放在右边。这里选择数组的最后一个元素作为枢轴。

2、quickselect函数:这是一个递归函数,用于在分区后选择第k个最大的元素。如果分区点正好是k,则返回前k个元素。如果分区点小于k,则递归处理右半部分,否则处理左半部分。

3、findTopNElements函数:这是主函数,用于处理特殊情况(如n小于等于0或n大于等于数组长度),并调用quickselect函数。

优先队列

使用优先队列(最小堆)算法找到前N个最大的元素,可以使用JavaScript中的MinHeap来实现。我们将数组中的元素依次插入到一个大小为N的最小堆中,如果堆的大小超过N,就移除堆顶元素(最小的元素)。最终,堆中存放的就是前N个最大的元素。

class MinHeap {  constructor() {      this.heap = [];  }
 insert(value) {      this.heap.push(value);      this.bubbleUp();  }
 bubbleUp() {      let index = this.heap.length - 1;      while (index > 0) {          let parentIndex = Math.floor((index - 1) / 2);          if (this.heap[parentIndex] <= this.heap[index]) break;          [this.heap[parentIndex], this.heap[index]] = [this.heap[index], this.heap[parentIndex]];          index = parentIndex;      }  }
 extractMin() {      if (this.heap.length === 1) return this.heap.pop();      const min = this.heap[0];      this.heap[0] = this.heap.pop();      this.sinkDown(0);      return min;  }
 sinkDown(index) {      const length = this.heap.length;      const element = this.heap[index];      while (true) {          let leftChildIndex = 2 * index + 1;          let rightChildIndex = 2 * index + 2;          let leftChild, rightChild;          let swap = null;
         if (leftChildIndex < length) {              leftChild = this.heap[leftChildIndex];              if (leftChild < element) swap = leftChildIndex;          }
         if (rightChildIndex < length) {              rightChild = this.heap[rightChildIndex];              if ((swap === null && rightChild < element) || (swap !== null && rightChild < leftChild)) {                  swap = rightChildIndex;              }          }
         if (swap === null) break;          [this.heap[index], this.heap[swap]] = [this.heap[swap], this.heap[index]];          index = swap;      }  }
 size() {      return this.heap.length;  }
 peek() {      return this.heap[0];  }}
function findTopNElements(arr, n) {  if (n <= 0) {      return [];  }  if (n >= arr.length) {      return arr.slice().sort((a, b) => b - a);  }
 const minHeap = new MinHeap();  for (let i = 0; i < arr.length; i++) {      minHeap.insert(arr[i]);      if (minHeap.size() > n) {          minHeap.extractMin();      }  }
 const result = [];  while (minHeap.size() > 0) {      result.push(minHeap.extractMin());  }  return result.sort((a, b) => b - a);  // 最后结果需要从大到小排序}
// 示例用法const arr = [3, 2, 1, 5, 6, 4];const n = 3;const topNElements = findTopNElements(arr, n);console.log(`前${n}个最大的元素:`, topNElements);


1、MinHeap类:实现了一个最小堆,包括插入元素、移除最小元素、获取堆的大小、查看堆顶元素等操作。

2、findTopNElements函数:这个函数使用最小堆来存储前N个最大的元素。如果堆的大小超过N,就移除堆顶元素。最终,堆中存放的就是前N个最大的元素。

3、示例用法:创建一个数组和N值,并调用findTopNElements函数来找到前N个最大的元素。最后输出结果。

相关文章
Commvault、Druva、Nasu...
Vue 辅助函数的作用...
AST 节点类型...
Proxy可以监听基本数据类型吗?...