High frequency algorithm interview questions
★★★ 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
Reference https://www.cnblogs.com/chengxiao/p/6129630.html
// 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--) { adjustHeap(arr, i, arr.length) } // 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 adjustHeap(arr, 0, j) } } // Adjustment reactor 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; // Judge address 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) } return 'not found' }
★★ 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