# High frequency algorithm (real interview question)

Posted by pcbytes on Fri, 14 Jan 2022 17:11:23 +0100

# ★★★ bubble sorting

Compare two from the start position for n rounds

• Basic Edition

```function bubbleSort (arr) {
// Execute round i + 1
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - 1; j++) {
// Compare the former with the latter in pairs
if (arr[j] > arr[j + 1]) {
// Swap two variable values
let tmp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = tmp
}
}
}
}
```
• Improved version

```function bubbleSort (arr) {
// Bubbling processes a maximum / minimum value each time, and i represents the position of the maximum value each time
for (let i = arr.length - 1; i > 0; i--) {
for (let j = 0; j < i; j++) {
if (arr[j] > arr[j + 1]) {
// Swap two variable values
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
}
}
```

# ★★ Select Sorting

Select the maximum / minimum value for n rounds each time

• Basic Edition

```function selectSort (arr) {
// Index of the minimum value of each
for (let i = 0, len_i = arr.length; i < len_i; i++) {
// Minimum index per round
let index = i

for (let j = i, len_j = arr.length; j < len_j; j++) {
if (arr[index] > arr[j]) {
// Minimum change
index = j
}
}
// Put the minimum value in the index of i
[arr[i], arr[index]] = [arr[index], arr[i]]
}
}
```
• Improved version

```function selectSort (arr) {
// Discharge lenth - 1 minimum
for (let i = 0, len_i = arr.length - 1; i < len_i; i++) {
let index = i
for (let j = i + 1, len_j = arr.length; j < len_j; j++) {
if (arr[index] > arr[j]) {
index = j
}
}
// Determine whether the minimum index has changed
if (index !== i) {
[arr[i], arr[index]] = [arr[index], arr[i]]
}
}
}
```

# ★★ insert sort

By default, an ordered array is incrementally inserted into the array

• Version one

```function insertSort (arr) {
// Index to insert
for (let i = 1, len_i = arr.length; i < len_i; i++) {
let cur = i
// Insert into a sequenced sequence
while (cur > 0 && arr[cur] < arr[cur - 1]) {
[arr[cur], arr[cur - 1]] = [arr[cur - 1], arr[cur]]
cur--
}
}
}
```
• Version 2

```function insertSort (arr) {
// Index to insert
for (let i = 1, len = arr.length; i < len; i++) {
let tmp = arr[i]

// Insert into a sequenced sequence
for (let j = i - 1; j >= 0 && arr[j] > tmp; j--) {
arr[j + 1] = arr[j]
}
arr[j + 1] = tmp
}
}
```

# ★★ Hill sort

Incremental insertion sort} the normal insertion sort interval is 1. Hill sort sets the interval to be greater than 1 by default, and then decreases to 1

```function shellSort (arr) {
let len = arr.length
let step = 1
let dis = 3
// Set maximum interval
while (step < len / dis) {
step = step * dis + 1
}

// Interval decrement
for (; step > 0; step = Math.floor(step / dis)) {
// Insertion sort of a single interval
for (let i = step; i < len; i++) {
let tmp = arr[i]
let j = i - step

while (j >= 0 && arr[j] > tmp) {
arr[j + step] = arr[j]
j -= step
}
arr[j + step] = tmp
}
}
}
```

# ★★ merge sort

Before sorting, split the array into two parts, and then merge and sort the two parts

```function mergeSort (arr) {
if (arr.length <= 1) return ;
let left = 0,
let right = arr.length - 1,
let mid = parseInt((left + right) * 0.5)

sort(arr, left, mid)
sort(arr, mid + 1, right)
merge(arr, left, mid, right)
}
function sort (arr, left, right) {
// Decompose into one element
if (left >= right) return ;
let mid = parseInt((left + right) * 0.5)

sort(arr, left, mid)
sort(arr, mid + 1, right)
merge(arr, left, mid, right)
}
function merge (arr, left, mid, right) {
// The merged [left, mid] [mid + 1, right] parts have been sorted
let i = left
let j = mid + 1
let tmp = []

// Insert the elements of an array in sequence
while (i <= mid && j <= right) {
// The equality here ensures the stability of the sorting algorithm (that is, the position of two equal numbers will not change after sorting)
if (arr[i] <= arr[j]) {
tmp.push(arr[i])
i++
} else {
tmp.push(arr[j++])
}
}
// Process remaining left / right elements
while (i <= mid) tmp.push(arr[i++])
while (j <= right) tmp.push(arr[j++])
for (let i = 0, len = tmp.length; i < len; i++) {
arr[left + i] = tmp[i]
}
}
```

# ★★★ quick sort

Before sorting, split the array into two parts according to the specified base point. One part is less than or equal to the base point and the other part is greater than the base point

• Version one

```function quickSort (arr) {
if (arr.length <= 1) return ;
let left = 0
let right = arr.length - 1

sort(arr, left, right)
}
function sort (arr, left, right) {
if (left >= right) return ;
let baseValue = arr[left]
let start = left
let end = right
while (start < end) {
// Find the index of the value on the right that is less than the base point
while (start < end && arr[end] >= baseValue) end--
// Find the index of the value greater than the base point on the left
while (start < end && arr[start] <= baseValue) start++
if (start < end) {
[arr[start], arr[end]] = [arr[end], arr[start]]
}
}
[arr[left], arr[start]] = [arr[start], arr[left]]
sort(arr, left, start - 1)
sort(arr, start + 1, right)
}
```
• Version 2

```function quickSort(arr) {
if (arr.length <= 1) return ;
let left = 0
let right = arr.length - 1

sort(arr, left, right)
}
function sort (arr, left, right) {
if (left >= right) return ;
let baseValue = arr[left]
let leftArr = []
let rightArr = []

for (let i = left; i <= right; i++) {
if (arr[i] <= baseValue) {
leftArr.push(arr[i])
} else {
rightArr.push(arr[i])
}
}
let mid = left + leftArr.length - 1
for (let i = 0, len = leftArr.length; i < len; i++) {
arr[left + i] = leftArr[i]
}
for (let i = 0, len = rightArr.length; i < len; i++) {
arr[mid + i + 1] = rightArr[i]
}
[arr[left], arr[mid]] = [arr[mid], arr[left]]
sort(arr, left, mid - 1)
sort(arr, mid + 1, right)
}
```

# ★★ heap sorting

Treat the array as a heap structure, where index = 0 is the root node

The child nodes of the node pointed to by index are 2 * index + 1, 2 * index + 20 - > 1, 2, 1 - > 3, 4, 2 - > 5, 6

The actual operation is to adjust the heap. You can learn about the data structure of the heap

```// Heap sort
function heapSort (arr) {
// Start from the last non leaf node to build a large top heap, that is, find the maximum number each time
for (let i = Math.floor(arr.length * 0.5 - 1); i >= 0; i--) {
}
// Putting the largest node at the end is equal to arranging the order, and building a large top heap for the remaining elements
for (j = arr.length - 1; j > 0; j--) {
[arr[0], arr[j]] = [arr[j], arr[0]]
// Most of them do not need to be adjusted, so start directly from the root node
}
}
function adjustHeap (arr, i, len) {
// k = 2 * k + 1 means that when two nodes are exchanged, the original heap structure will be confused, and the child nodes need to be readjusted
let cnt = 0
for (let k = 2 * i + 1; k < len; k = 2 * k + 1) {
// Find the largest node between the left child node and the right child node
if (k + 1 < len && arr[k] < arr[k + 1]) k++
// Determine whether to exchange with child nodes
if (arr[k] > arr[i]) {
[arr[k], arr[i]] = [arr[i], arr[k]]
// After the exchange is completed, the next level node shall be readjusted
i = k
} else {
break ;
}
}
}
```

# ★★★ Fibonacci sequence

Fibonacci sequence 0 1 1 2 3 5 8 13 Item n is the sum of items n-1 and n-2. The first item is 0 and the second item is 1

• Use cycle

```function fibonacci (n) {
if (n <= 2) return n - 1
let n1 = 0, n2 = 1

for (let i = 2; i < n; i++) {
[n1, n2] = [n2, n1 + n2]
}
return n2
}
```
• Use recursion

Large memory consumption

```function fibonacci (n) {
return n <= 2 ? n - 1 : Fibonacci(n - 1) + Fibonacci(n - 2)
}

// Set cache
let cache = {}
function fibonacci (n) {
if (n <= 0) return 0
if (n <= 2) return n - 1
if (cache[n]) return cache[n]

return cache[n] = Fibonacci(n - 1) + Fibonacci(n - 2)
}
```

# ★★ Hanoi Tower problem

Hanoi Tower rule reference https://baike.baidu.com/item/%E6%B1%89%E8%AF%BA%E5%A1%94/3468295

• Recursive solution

```// The three columns are a, B, C, and a is the initial position
function hanoi (n, current = 'A', temp = 'B', target = 'C') {
if (n <= 0) return 0
let sum = 1

sum += hanoi(n - 1, current, target, temp)
console.log(current + ' ---> ' + target)
sum += hanoi(n - 1, temp, target, current)
return sum
}
```

# ★★ merge two ordered arrays

Merge method of direct reference merge sort

```function mergeArr (arr1, arr2) {
let result = []
// p1 and p2 are the indexes of arr1 and arr2, respectively
let p1 = p2 = 0
let len1 = arr1.length
let len2 = arr2.length

while (p1 < len1 && p2 < len2) {
arr1[p1] <= arr2[p2] ? result.push(arr1[p1++]) : result.push(arr2[p2++])
}
while (p1 < len1) result.push(arr1[p1++])
while (p2 < len2) result.push(arr2[p2++])
return result
}
```
• API version

```function mergeArr (arr1, arr2) {
// sort custom collation
return (arr1.concat(arr2)).sort((a, b) => a - b)
}
```

# ★★ duplicate numbers in the array

Array de duplication can be referenced https://segmentfault.com/a/1190000016418021

• Simple version

```function noRepeat (arr) {
return [...new Set(arr)]
}
```
• Circular version

```function noRepeat (arr) {
let result = []

// n+1 non repeating element
for (let i = 0, len_i = arr.length; i < len_i; i++) {
let isNoRepeat = true
for (let j = 0, len_j = result.length; j < len_j; j++) {
// If there are only basic data types in the array, you can directly use = = =
isNoRepeat = !isEqual(arr[i], result[j])
if (!isNoRepeat) break;
}
if (isNoRepeat) result.push(arr[i])
}
return result;
}

// Methods used
function isEqual (obj1, obj2) {
// Judge whether the types are the same
let type = getType(obj1)
if (type !== getType(obj2)) return false;
// Judge basic data type value
if (typeof obj1 !== 'object') return obj1 === obj2;
if (obj1 === obj2) return true;

// Judge whether the values are the same
switch (type) {
// object
case '[object Object]':
// Get traversable property
let keys1 = Object.keys(obj1)
let keys2 = Object.keys(obj2)
if (keys1.length !== keys.length) return false
// Equal length
for (let i = 0, len = keys1.length; i < len; i++) {
let key = keys1[i]
if (!isEqual(obj1[key], obj2[key])) return false;
}
break;
// Map
case '[object Map]':
// Set
case '[object Set]':
// Convert to array
obj1 = Array.from(obj1)
obj2 = Array.from(obj2)
// array
case '[object Array]':
if (obj1.length !== obj2.length) return false;
for (let i = 0, len = obj1.length; i < len; i++) {
if (!isEqual(obj1[i], obj2[i])) return false;
}
break;
// ...
default: break;
}
return true;
}
function getType (obj) {
// You can determine the data type of array Map Set
return Object.prototype.toString.call(obj)
}
```
• Marked version

```function noRepeat (arr) {
let result = []
// Multiple data types can be determined using tags and maps
// Here, you can also use the WeakMap weak reference to check the data js WeakMap type yourself
const flag = new Map()

for (let i = 0, len = arr.length; i < len; i++) {
// Preliminary judgment
if (!flag.has(arr[i])) {
let isNoRepeat = true
// Basic data type direct insertion
// Reference data type
if (typeof arr[i] === 'object') {
for (let j = 0, len_j = result.length; j < len_j; j++) {
isNoRepeat = !isEqual(arr[i], result[j])
if (!isNoRepeat) break;
}
}
// No repetition
if (isNoRepeat) {
result.push(arr[i])
flag.set(arr[i], true)
}
}
}
return result
}
```

# ★★ intersection of two arrays

Intersection is the same part, not two sets, so the final intersection needs to retain the same elements with different indexes

• Basic Edition

```function intersection (arr1, arr2) {
let flag = {}
let result = []

for (let i = 0, len_i = arr1.length; i < len_i; i++) {
let item = arr1[i]
// It's OK to search whether indexOf or includes is used
for (let j = 0, len_j = arr2.length; j < len_j; j++) {
// To determine equality, it is recommended to use the previously encapsulated isEqual method
// isEqual(arr1[i], arr2[i])
if (item === arr2[j] && !flag[j]) {
result.push(item)
flag[j] = true
break;
}
}
}
return result
}
```
• Map markup

```// Defect if the element value has a reference data type, an error may occur
function intersection (arr1, arr2) {
let map = new Map()
let result = []

for (let i = 0, len = arr1.length; i < len; i++) {
let item = arr1[i]
if (map.has(item)) map.set(item, map.get(item) + 1)
else map.set(item, 1)
}
for (let i = 0, len = arr2.length; i < len ;i++) {
let item = arr2[i]
if (map.has(item)) {
result.push(item)
map.set(item, map.get(item) - 1)
}
}
return result
}
```
• API version

```// It is more suitable to find the intersection of two sets
function intersection (arr1, arr2) {
// return noRepeat(arr1).filter(v => arr2.includes(v))
return [...new Set(arr1)].filter(v => arr2.includes(v))
}
```

# ★★ rotate array

In reverse order? Or rotate the array to the right by k steps, and change the original array directly without returning a new array?

• Reverse order

```function reverse (arr) {
let len = arr.length

for (let i = 0, mid = parseInt(len * 0.5); i < mid; i++) {
[arr[i], arr[len - i - 1]] = [arr[len - i - 1], arr[i]]
}
return arr
}
```
• Rotate k steps

```function rotateArr (arr, k) {
let len = arr.length
let tmp = [...arr]

if (k < 0) k = (k % len) + len
for (let i = 0; i < len; i++) {
let index = (i + k) % len
arr[index] = tmp[i]
}
return arr
}
```

# ★★ sum of two numbers

Given an integer array nums # and a target value target, please find the two integers with sum as the target value in the array and return their array subscripts.

You can assume that each input will correspond to only one answer. However, you cannot reuse the same elements in this array.

Example nums = [2, 7, 11, 15] target = 9, then the result returns [0, 1], which is the subscript of 2 and 7

```function twoSum (arr, target) {
let map = new Map()

for (let i = 0, len = arr.length; i < len; i++) {
let diff = target - arr[i]
if (map.has(diff)) {
return [map.get(diff), i]
}
map.set(arr[i], i)
}
}
```

# ★★ realization idea of climbing steps

Suppose you are climbing stairs. You need n steps to reach the roof.

You can climb one or two steps at a time. How many different ways can you climb to the roof?

Note: given n is a positive integer.

Example n = 2 -- > 2 two methods 1st order + 1st order and 2nd order

• Realization idea

```// First of all, the title requires Mei to list all the steps to climb the stairs, and you can climb only one step at a time (no matter how you climb, you can only climb one step to the roof)
// This can give a basic idea to climb once (1 or 2) - > climb the remaining steps. The termination condition is that the number of remaining steps is 0
function climb (n) {
if (n === 0) return 1  // One return here represents a way to climb to the roof
climb(n - 1)  // Climb the remaining steps after climbing step 1
if (n - 2 >= 0) {
climb(n - 2)  // After climbing 2 steps, climb the remaining steps. At this time, judge whether the number of remaining steps is greater than or equal to 2
}
}

// Improve the termination condition to n < = 2
function climb (n) {
if (n <= 0) return 0    // Direct termination
if (n <= 2) return n    // There is one solution for the remaining first order and two solutions for the second order

return climb(n - 1) + climb(n - 2)
}

// At this point, you can find that climb(n - 1) calls climb(n - 2) internally, and climb(n) also calls climb(n - 2)
// You might as well save the calculation results
let cache = {}
function climb (n) {
if (n <= 0) return 0    // Direct termination
if (n <= 2) return n    // There is one solution for the remaining first order and two solutions for the second order
if (cache[n]) return cache[n]

return cache[n] = climb(n - 1) + climb(n - 2)
}
// be accomplished```