A pile of front-end algorithms--counting sort

Heaps can be divided into two types : min heap and max heap .

In a min-heap, the value of each parent node must be less than or equal to the value of its child node, that is, the root node is the minimum value in the entire heap.

In a max heap, the value of each parent node must be greater than or equal to the value of its child node. That is to say, the root node is the maximum value in the entire heap.

The following example illustrates the concept of heap:

Min heap:

Suppose we have a min-heap with the following elements: [5, 7, 10, 12, 15, 17, 20]

Its binary tree representation is as follows:

         5
       /   \
     7      10
   /  \    /  \
 12   15  17  20

In a min-heap, the value 5 of the root node is the smallest value in the entire heap. And, the value of each parent node is less than or equal to the value of its child node.

Max heap:

Suppose we have a max-heap with the following elements: [30, 25, 20, 15, 10, 5]

Its binary tree representation is as follows:

        30
       /   \
     25      20
   /   \    /
 15    10  5

In a max-heap, the value 30 of the root node is the maximum value in the entire heap. And, the value of each parent node is greater than or equal to the value of its child node.

Heaps can be used in many algorithms and data structures, such as heap sort, priority queue, etc.

For more details, please search " " on WeChat前端爱好者 and click me to view .

What problem is the heap used to solve?

The Heap data structure can be used to solve the following problems:

Heap Sort:

An unordered array can be converted into an ordered array by using heap sorting. The time complexity of heap sort is O(nlogn), which is an efficient sorting algorithm.

Priority Queue:

A priority queue is a special queue where each element has a priority associated with it. The heap can implement the basic operations of the priority queue, such as inserting elements, deleting elements with the highest priority, etc. Common applications include task scheduling, event processing, etc.

Shortest path and minimum spanning tree problems in graph algorithms:

In some graph algorithms, such as Dijkstra's algorithm and Prim's algorithm, it is necessary to find the shortest path or minimum spanning tree.

The heap can be used to maintain a set of pending nodes and select the node with the smallest weight each time the next node is selected.

Find the median:

Finding the median in a series of numbers is a common problem. The median can be found efficiently using heaps, where min-heap and max-heap can store the larger and smaller half of the numbers respectively.

Merge K ordered arrays:

When multiple ordered arrays need to be merged, the heap can be used to improve efficiency. By putting the smallest element of each array into the heap, and then popping the top element of the heap each time for merging, the merging operation can be completed with a time complexity of O(nlogk).

These are just some examples of heap applications. Heaps can also be used to solve many other problems, especially those that require efficient finding of the smallest or largest element.

Example: Inventory Management III O(n) time complexity

Native API

leetcode link : https://leetcode.cn/problems/zui-xiao-de-kge-shu-lcof/

The warehouse manager records the product inventory table in the form of an array stock, where stock[i] represents the inventory balance of the corresponding product. Please return the cnt items with the smallest remaining inventory in any order.

Example 1:

输入:stock = [2,5,7,4], cnt = 1
输出:[2]

Example 2:

输入:stock = [0,2,3,6], cnt = 2
输出:[0,2][2,0]

hint:

0 <= cnt <= stock.length <= 10000
	0 <= stock[i] <= 10000

Idea: Sort first, then get the value

/**
 * @param {number[]} stock
 * @param {number} cnt
 * @return {number[]}
 */
var inventoryManagement = function(stock, cnt) {
    
    
    // 先排序,然后取值
    return stock.sort((a,b)=>a-b).slice(0,cnt)
};

Using the heap: counting sort – trading space for time

/**
 * @param {number[]} stock
 * @param {number} cnt
 * @return {number[]}
 */
var inventoryManagement = function(stock, cnt) {
    
    
    // 先排序,然后取值
    return  countingSort(stock,cnt,10000)
};

const countingSort = (arr,k,length)=>{
    
    
    // 将新开辟一个空间,将输入的数据存储到空间
    let bucket = new Array(length) 
    let sortedIndex = 0
    let arrLen = arr.length
    let bukectLength = length

    // stock [2,5,7,4] 原抬款组中下标对应的值 对应此处的下标
    for(let i = 0; i < arrLen;i++){
    
    
        if(!bucket[arr[i]]){
    
    
            bucket[arr[i]]= 0
        }
        bucket[arr[i]] ++
    } // bucket [0,0,1,0,1,1,0,1,]

    let res = [] 
    for (let j = 0; j < bukectLength;j++){
    
    
        while(bucket[j]-- > 0 && sortedIndex < k){
    
    
            res[sortedIndex++] = j
        }

        if(sortedIndex === k){
    
    
            break
        }
    }

    return res
}

Extension 1: JavaScript slice method

In JavaScript, slice()an array method that extracts a specified range of elements from the original array and returns a new array. It does not modify the original array, but returns a shallow copy.

slice()The method accepts two parameters: starting index and ending index (optional). The start index specifies the starting position of the interception, including the element corresponding to the index; the end index specifies the end position of the interception, but does not include the element corresponding to the index.

Usage example:

const fruits = ['apple', 'banana', 'orange', 'grapefruit', 'kiwi'];

// 截取索引1到3之间的元素(不包括索引3)
const slicedFruits = fruits.slice(1, 3);
console.log(slicedFruits); // 输出: ['banana', 'orange']

// 不传递结束索引,则截取从起始索引到数组末尾的所有元素
const slicedFruits2 = fruits.slice(2);
console.log(slicedFruits2); // 输出: ['orange', 'grapefruit', 'kiwi']

// 负数索引表示从数组末尾开始计算,-2表示倒数第二个元素
const slicedFruits3 = fruits.slice(-2);
console.log(slicedFruits3); // 输出: ['grapefruit', 'kiwi']

// 可以将slice()用于字符串
const str = "Hello, World!";
const slicedStr = str.slice(7, 12);
console.log(slicedStr); // 输出: "World"

Precautions:

  • If the end index is less than the start index, an empty array is returned.
  • The elements of the original array are not affected slice()by the method, it just returns a new copy of the array.
  • slice()The method is also applicable to strings and can intercept character substrings within the specified range.

Extension 2: Counting sort

Counting Sort is a sorting algorithm with linear time complexity (O(n+k)), where n is the number of elements to be sorted, and k is the value range of the elements to be sorted. Counting sort is suitable for sorting integer arrays with a small range.

The basic idea of ​​counting sort is to count the number of times each element appears, and then put the elements back to the correct position based on the statistical information. It uses an additional count array to store the number of occurrences of each element, and then determines the final position of each element in the sorted array by accumulating the values ​​in the count array.

Here are sample steps for counting sort:

  1. Count the number of occurrences of each element: traverse the array to be sorted, count each element, and store the counting results in the counting array at the corresponding index position.

  2. Accumulating count array: Perform an accumulation operation on the count array, and the value of each position is equal to the sum of the values ​​of all previous positions, so that the final position of each element in the sorted array can be determined.

  3. Sorting: Create a temporary array of the same size as the array to be sorted, traverse the array to be sorted, determine the position of each element in the temporary array based on the value in the count array, and place the elements into the temporary array.

  4. Copy the elements in the temporary array back to the original array: Copy the elements in the temporary array back to the original array in order, that is, complete the sorting.

Here is an example code for counting sort (using JavaScript):

function countingSort(arr) {
    
    
  const len = arr.length;
  if (len <= 1) {
    
    
    return arr;
  }

  // 找出待排序数组中的最大值
  let max = arr[0];
  for (let i = 1; i < len; i++) {
    
    
    if (arr[i] > max) {
    
    
      max = arr[i];
    }
  }

  // 创建计数数组,并统计每个元素的出现次数
  const countArray = new Array(max + 1).fill(0);
  for (let i = 0; i < len; i++) {
    
    
    countArray[arr[i]]++;
  }

  // 累加计数数组
  for (let i = 1; i <= max; i++) {
    
    
    countArray[i] += countArray[i - 1];
  }

  // 创建临时数组存储排序结果
  const tempArray = new Array(len);

  // 排序
  for (let i = len - 1; i >= 0; i--) {
    
    
    const value = arr[i];
    const index = countArray[value] - 1;
    tempArray[index] = value;
    countArray[value]--;
  }

  // 将临时数组复制回原始数组
  for (let i = 0; i < len; i++) {
    
    
    arr[i] = tempArray[i];
  }

  return arr;
}

// 使用示例
const array = [5, 8, 2, 1, 9, 3, 5];
const sortedArray = countingSort(array);
console.log(sortedArray); // 输出: [1, 2, 3, 5, 5, 8, 9]

The advantage of counting sort is that it is not a comparison-based sorting algorithm, so in some cases it can be faster than other sorting algorithms. However, the disadvantage of counting sort is that it has certain requirements on the value range of the input data and requires additional space to store the counting array and temporary array.

Guess you like

Origin blog.csdn.net/BradenHan/article/details/135418381