Front end - algorithm

foreword

Like the data structure, the algorithm test questions are also favored by the interviewers. In many cases, we can discuss with the interviewer the appropriate programming method according to the characteristics of the questions. Usually, sorting and searching are the focus of the algorithm test during the interview. Two points Searching, merging, and quick sorting must be able to be accurate at any time, and write their codes completely.
Factors that affect the standardization of code: writing, layout, naming
code integrity: boundary judgment must be added!

Array articles:

The basics of arrays :

let arr1 = [1, 2, 10, 30]
let arr2 = [3, 4, 50, 90]
let arr3 = ['banana', 'apple', 'peach']
// arr1.concat(arr2) // [ 1, 2, 10, 30, 3, 4, 50, 90 ] 合并数组
// const a = arr1.entries() // Object [Array Iterator] {} 返回一个数组迭代对象,可用for of遍历
// arr1.fill('bob')  // [ 'bob', 'bob', 'bob', 'bob' ] 使用一个固定值来填充数组,改变原数组
// const flag = arr1.every(item => { return item >= 1 }) // true 数组内每一个元素都满足>=1返回true,有一个不满足就返回flase,并不再遍历,不改变原数组
// const flag = arr1.some(item => { return item > 11 }) // true 数组内只要有一个元素满足条件就返回true,不再遍历数组,都不满足返回false,不改变原数组
// const newArr = arr1.filter(item => { return item > 6 }) // [ 10, 30 ] 返回满足判断条件的元素组成的数组,不改变原数组
// const target = arr1.find(item => { return item > 99 }) // 10 返回满足条件的第一个元素,找到目标元素便不再遍历,无就返回undefind,不改变原数组
// const targetIndex = arr1.findIndex(item => {return item >= 10}) // 2 返回满足条件的元素的索引,无就返回-1
// const newArr = arr1.forEach(item =>{ if(item===2) return ;console.log('执行')}) // 执行 执行 执行 将数组内的每个元素都执行一次函数,这里的return相当于continue,跳出循环要使用try catch实现,改变元素组,没有返回值
try{
    
    
        array.forEach(function(item,index){
    
    
                if(item == "third"){
    
    
                        throw new Error("ending");//报错,就跳出循环
                }else{
    
    
                        console.log(item);
                }
        })
}catch(e){
    
    
        if(e.message == "ending"){
    
    
                console.log("结束了") ;
        }
}
// const newArr2 = Array.from('HBGSV') // [ 'H', 'B', 'G', 'S', 'V' ]将一个字符串转化为数组
// const newArr = new Set(arr1)
// const newArr2 = Array.from(newArr, x => x * 10) // [ 10, 20, 100, 300 ]将map结构转化为数组结构,第二个参数是一个函数,数组内的每一个数都会执行它
// const flag = arr1.includes(2) // true 看数组内是否包含2这个元素,返回布尔值
// const flag = arr1.indexOf(10) // 2 返回指定元素在数组内的索引位置,无就返回-1
// const flag = Array.isArray(arr1) // true 判断一个对象是否是一个数组
// const string1 = arr1.join() // 1,2,10,30 将一个数组转化为一个字符串,参数不写默认以逗号分隔
// arr1.keys() // Object [Array Iterator] {}返回一个实现Iterator接口的对象,需要调用.next() // { value: 0, done: false } .value: // 0
// const index = arr1.lastIndexOf(10) // 2 返回目标元素在数组里出现的最后一个位置
// const newArr = arr1.map(item => { return item * 2 }) // [ 2, 4, 20, 60 ] 返回处理过的数组,不改变原数组
// const popRes = arr1.pop() // 30 删除数组最后一个元素,并返回被删除的元素
// const newArrLength = arr1.push(1,2) // 6 向数组的末尾添加元素,并返回新数组的长度
// const arrTotal = arr1.reduce((total, current) => { return total + current }, 0) // 43 返回数组内所有元素计算的结果(从左到右) 第一个参数是一个函数,函数有两个参数,分别是:上一次相加的结果和当前正要加的值,另一个参数是相加的初始值
// const arrTotal = arr1.reduceRight((total, current) => { return total - current }, 0) // -43 功能和上一个一样,不同之处是它(从右到左)
// const newArr = arr1.reverse() // [ 30, 10, 2, 1 ] 颠倒数组中的顺序,返回颠倒顺序的数组,并改变原数组!!
// const newArr = arr3.sort() // [ 'apple', 'banana', 'peach' ] 对数组内的元素(字母)进行升序排序,但是数字排序会出错(下一个),返回排好顺序的数组,并改变原数组!!
// const newArr = arr1.sort((a, b) => { return a - b }) // [ 1, 2, 10, 30 ] 对数组内的数字执行排序时要传入一个函数,a-b为升序,b-a为降序,返回排好顺序的数组,并改变原数组!!
// const shiftRes = arr1.shift() // 1 删除并返回数组的第一个元素 改变原数组
// const newArrLength = arr1.unshift(99) // 5 向数组的开头添加元素,返回数组的新长度 改变原数组
// const newArr = arr1.slice(0, 2) // [ 1, 2 ] 两个参数分别是切的开始位置和结束位置,返回由选定的元素组成的新数组,不改变原数组
// array.splice(index,howmany,item1,.....,itemX) // index:删除或添加函数的位置;howmany:从index位置删除howmany个元素(必须),不写就直接删除index之后的所有元素(非必须);item1,.....:为添加的元素,不写就不添加(非必须),函数返回被删除的元素
// const newArr = arr1.splice(2,0,99) // [] 返回值为删除的元素所组成的数组,这里我们从数组为2的位置插入(删除)元素,删除0个元素,添加99这个元素,改变原素组!!
// const newString = arr1.toString() // 1,2,10,30 将数组转化为字符串,以逗号分隔数组元素,不改变原数组
// const newString = arr1.valueOf() // 返回元素本身[ 1, 2, 10, 30 ],运算是先调用valueOf再调用toString,日期对象的话会返回1970 年 1 月 1 日到当前对象的毫秒数

1. Find the repeated numbers in the array

Description of the problem : Find the repeated numbers in the array, return the repeated value if it is available, and return -1 if it is not available, such as [3,4,5,3,7,9,4], return 3 or 4 are correct.
Idea : The attribute name of the object is unique

function getRes() {
    
    
  const arr = [3, 4, 5, 3, 7, 9, 4]
  const len =  arr.length
  const obj = {
    
    }
  let resArr = []
  if (Array.isArray(arr) && len > 0) {
    
    
    for (let i = 0; i < len; i++) {
    
     
      if (obj[arr[i]] === undefined) {
    
    
        obj[arr[i]] = 1
      }
      else {
    
    
        obj[arr[i]]++
      }
    }

    for (let key in obj) {
    
    
      if (obj[key] >= 2) {
    
    
        resArr.push(key)
      }
    }

    return resArr.length === 0 ? -1 : resArr[0]
  }
  else {
    
    
    return -1
  }
}

console.log(getRes()) // 3

2. Build a product array

Problem description : Given an array A[0,1,…,n-1], please construct an array B[0,1,…,n-1], where the elements in B B[i]
=A[0 ] A[1] ...*A[i-1] A[i+1] ... A[n-1] (to put it bluntly: after removing i, the product of the numbers on the left and right of the array [i]).
Division cannot be used. (Note: It is stipulated that B[0] = A[1] * A[2] * ... * A[n-1],
B[n-1] = A[0] * A[1] * ... * A[n -2];)
For the case where A has length 1, B is meaningless and cannot be constructed, so this case will not exist.

Idea : First find the product of the first i numbers (prefix multiplication), then find the product of the last i numbers (suffix product), and finally get B[i] by adding the prefix * suffix.


function getRes() {
    
    
  let arr = [1, 2, 3, 4, 5] // 输入数组
  
  let preArr = []  // 前缀乘积
  preArr[0] = 1
  for (let i = 1; i < arr.length; i++) {
    
    
    preArr[i] = preArr[i - 1] * arr[i - 1]
  }

  let sufArr = [] // 后缀乘积
  sufArr[arr.length - 1] = 1
  for (let j = arr.length - 2; j >= 0; j--) {
    
    
    sufArr[j] = sufArr[j + 1] * arr[j + 1]
  }

  let resArr = [] // 结果数组
  for (let i = 0; i < arr.length; i++) {
    
    
    resArr[i] = preArr[i] * sufArr[i]
  }

  return resArr
}

console.log(getRes())

3. Search in two-dimensional array :

Problem description : In a two-dimensional array (each one-dimensional array has the same length), each row is sorted in ascending order from left to right, and each column is sorted in ascending order from top to bottom. Please complete a function, input such a two-dimensional array and an integer, and judge whether the integer is contained in the array.
[
[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]
]
Given target = 7, return true.

Given target = 3, returns false.
Idea : Start searching from the upper right corner (the lower left corner is also possible, because we can eliminate a row or a column without taking a step, but it is not efficient to eliminate a row or a column with each step in the lower right corner and upper left corner), and go to the left first , when you encounter a number larger than target, continue to go left, and when you encounter a number smaller than target, go down, and you can find the target. Finally, ES6 has a method to convert a multidimensional array into a one-dimensional array, arr.flat (the dimension of the array), such as [[1, 2, 8, 9], [2, 4, 9, 12, [1,1, 1]]]. flat( 2 ) // [1, 2, 8, 9, 2,4, 9, 12, 1, 1,1] , if you have no idea about two-dimensional, it is very simple to convert to one-dimensional , if the interviewer can solve it like this. . .

function Find(target, array) {
    
    
  if (Array.isArray(array) && array.length > 0 && Array.isArray(array[0]) && array[0].length > 0) {
    
    
    let x = array.length // 获取二维数组的行数
    let y = array[0].length // 获取二维数组的列数
    // 从二维数组的右上角开始查找target
    let i = array[0].length - 1 // 列位置
    let j = 0 // 行位置
    while (i >= 0 && j <= x - 1) {
    
    
      if (target < array[i][j]) {
    
     // 如果目标值前一个数小,往左走
        i--
      }
      else if (target > array[i][j]) {
    
     // 如果目标值比下一个数大,往下走
        j++
      }
      else {
    
     // 不大也不小了,说明相等了,找到目标值,返回true
        return true
      }
    }
    return false // 循环完没找到,说明没有,return false
  }
}
const res = Find(15, [
  [1, 2, 8, 9],
  [2, 4, 9, 12],
  [4, 5, 10, 13],
  [6, 8, 11, 15]
])
console.log(res) // true

4. The sum of two numbers

Problem description : Given an array of integers, please find two numbers in the array that add up to the target value.
The function twoSum you give needs to return the subscripts (index1, index2) of these two numbers, and it needs to satisfy that index1 is less than index2.. Note: The subscript starts from 1.
Assume that there is only a unique solution in the given array
. For example:
the given array is {20, 70, 110, 150}, and the target value is 90.
Output index1=1, index2=2

Idea : At the beginning, the brute force solution will definitely be used. The two for loops will be solved quickly, but only after looking at the optimal solution, you will know that this problem can be solved by using the hash table. Put the value and index value in the hash table, and the target subtracts the number in the array in turn. If the result happens to have been stored in the hash table (that is, 6-2 = 4; 4 has not yet added 2 in the hash table Save it in, but the next polling 6-4 = 2, 2 was just put in in the previous round, there is, and the result array is obtained), then it is found, and the index in the hash table and the index currently traversed are returned That's it.

function twoSum(numbers, target) {
    
    
let len =  numbers.length 
if (Array.isArray(numbers) && len > 0){
    
    
let resArr = new Map()
  let res = undefined
  for (let i = 0; i < len; i++) {
    
    
    res = target - numbers[i]
    if (resArr.has(res)) {
    
    
      return [resArr.get(res) + 1, i + 1]
    }
    resArr.set(numbers[i],i)
  }
  }
}
twoSum([3, 2, 4], 6) // [ 2, 3 ]

5. Put the 0 in the array at the end of the array

Problem Description : Put 0 in the array at the end of the array
For example: Input: [ 9, 10, 0, 1, 2, 2, 3, 0, 12] Output: [ 9, 10, 1, 2, 2, 3 , 12, 0, 0 ]
Idea : Use two pointers, such as pointer A and pointer B, pointer A follows the for loop to normally point to each item in the array, and pointer B follows when pointer A is not pointing to 0 Pointing down, once B points to 0 in the array, it stops moving. When pointer A points to the next value that is not 0, it is exchanged with the value pointed to by pointer B. Pointer A is directly assigned a value of 0, and gradually the value that is not 0 The value is placed at the front of the array, and 0 is placed at the end of the array

function twoSum(nums) {
    
    
  let tem = 0
  for (let i = 0; i < nums.length; i++) {
    
    
    if (nums[i] !== 0) {
    
     // 当tem指到0了tem就不移动,让i++
      if (nums[tem] == 0) {
    
    
        nums[tem] = nums[i]
        nums[i] = 0
      }
      tem++ // 当指到数组中不是0的数tem才继续移动
    }
  }
  return nums
}

twoSum([9, 10, 1, 0, 2, 2, 0, 3, 12])

6. Fibonacci sequence

Description of the problem : Everyone knows the Fibonacci sequence (except for the first three items, the subsequent items are equal to the sum of the first two items, and now an integer n is required, please output the nth item of the Fibonacci sequence Idea: You
can use Recursive implementation, advantages: high code readability, disadvantages: high time complexity and space complexity, and more repetitive calculations; so use loop plus three numbers to achieve

function getRes(n) {
    
    
  if (n < 2) {
    
    
    return n
  }
  let first = 1;
  let second = 1;
  let res = 0;
  for (let i = 2; i < n; i++) {
    
    
    res = first + second
    first = second
    second = res
  }
  return res
}

6.1 Frog Jumping Stairs Problem

Description of the problem : A frog can jump up to 1 step or 2 steps at a time. Find the total number of jumping methods for the frog to jump up an n-level step.
The answer needs to be modulo 1e9+7 (1000000007). If the initial calculation result is: 1000000008, please return 1.
Analysis:
When n=1, the result is 1
; when n=2, the result is 2;
when n=3, the result is 3
; when n=4, the result is 5;
when n=5, the result is 8
...
you can get the law when n>= At 3, there is f(3) = f(2) + f(1), that is, f(n) = f(n-1) + f(n-2); that is, the Fibonacci sequence

function qwJump(n) {
    
    
    if (n <= 1) {
    
    
        return 1
    }
    if (n === 2) {
    
    
        return 2
    }
    let res = 0
    let t1 = 1
    let t2 = 2
    for (let i = 3; i <= n; i++) {
    
    
        res = (t1 + t2) % 1000000007
        t1 = t2
        t2 = res
    }
    return res
}

Rectangle Covering Algorithm:
Use 2 1 small rectangles to cover 2 n large rectangles, requiring no overlap
f(8) = f(7)+f(6) is still the Fibonacci sequence.

6.2 The problem of abnormal jumping of frogs (dynamic programming)

Description of the problem : A frog can jump up to 1 step, 2 steps, 3 steps...or n steps. Find the total number of jumping methods for the frog to jump up an n-level step.
Ideas :

  • n=1 there is 1 way to jump
  • n=2 There are 2 ways to jump
  • n=3 There are 4 ways to jump
  • n=4 There are 8 ways to jump
  • n=5, there are 16 jumping methods
  • ...
    From the law, n = 2*(n-1), so we can use dynamic programming:
function jump2(n) {
    
    
    const dp = Array.from(new Array(n + 1), () => 0);
    dp[2] = 2;
    for (let i = 3; i < n + 1; i++) {
    
    
        dp[i] = 2 * dp[i - 1];
    }
    return dp[n];
}
console.log(jump2(4))  // 8

7. Arrange the array into the smallest number

Problem description : Input an array of positive integers, concatenate all the numbers in the array to form a number, and print the smallest one among all the numbers that can be concatenated. For example, input the array [3, 32, 321], then print out that the smallest number that these three numbers can form is 321323.
Idea : Use two for loops, one pointing to the previous number of the array, and the other pointing to the next number of the array, a string is composed of the previous number and the next number, and the size of the two strings is compared. If the latter one is larger, then use the third variable to change the position, and the loop ends, and the result is obtained

function getRes(numbers) {
    
    
  let len = numbers.length
  let t = 0
  let str = ''
  for (let i = 0; i < len; i++) {
    
    
    for (let j = i + 1; j < len; j++) {
    
    
      let s1 = `${
      
      numbers[i]}${
      
      numbers[j]}`
      let s2 = `${
      
      numbers[j]}${
      
      numbers[i]}`
      if (parseInt(s1) > parseInt(s2)) {
    
    
        t = numbers[i]
        numbers[i] = numbers[j]
        numbers[j] = t
      }
    }
  }
  for (let i = 0; i < len; i++) {
    
    
    str += `${
      
      numbers[i]}`
  }
  return str
}

9. The sum of three numbers

Problem description : Given an array nums containing n integers, determine whether there are three elements a, b, c in nums, making a + b + c = 0? Find all triples that satisfy the condition and are not repeated.

Note: Duplicate triplets are not allowed in the answer.
For example, given the array nums = [-1, 0, 1, 2, -1, -4],

The set of triples that meet the requirements is:
[
[-1, 0, 1],
[-1, -1, 2]
]
Idea : first sort the given array and arrange it from small to large, which is convenient for the current sum Move the left pointer for <target, and move the right pointer for sum> taget. The idea of ​​the sum of three numbers (using sorting plus pointer) is the same as the sum of two numbers (using hash), using a+b = c, c -b = a, just find a in the array.

function threeSum(nums) {
    
    
  let num2 = nums.sort((a, b) => {
    
     return a - b })
  let resArr = []
  let len = nums.length
  for (let i = 0; i < len-2; i++) {
    
    
    let target = -num2[i]
    let left = i + 1
    let right = len - 1
    // let target = left + right
    if (num2[i] === num2[i - 1]) {
    
      // 前面出现过的数,那结果肯定有了,不用再去遍历了
      continue;
    }
    while (left < right) {
    
    
      let sum = num2[left] + num2[right]

      if (sum < target) {
    
    
        left++
      }
      else if (sum > target) {
    
    
        right--
      }
      else {
    
    
        resArr.push([num2[i], num2[left], num2[right]])
        while (num2[left] === num2[left + 1]) {
    
      // 排除重复的结果
          left++
        }
        left++
        while (num2[right] === num2[right - 1]) {
    
    
          right--
        }
        right--
      }
    }
  }
  return resArr
};

console.log(threeSum([-1, 0, 1, 2, -1, -4]))
输出:[ [ -1, -1, 2 ], [ -1, 0, 1 ] ]

10. Find the minimum element of the rotated array

Search in general order, the time complexity is O(n), use binary search time complexity is O(logn)

function minNumberInRotateArray(rotateArray){
    
    
    const length = rotateArray.length;
    if (!length) {
    
    
        return 0;
    }
 
    let left = 0, right = length - 1;
    while (left < right) {
    
    
        let mid = Math.floor((left + right) / 2);
 
        // 子数组有序
        if (rotateArray[left] < rotateArray[right]) {
    
    
            return rotateArray[left];
        }
 
        // 左子数组有序,最小值在右边
        // 那么mid肯定不可能是最小值(因为rotateArray[mid]大于rotateArray[left])
        if (rotateArray[left] < rotateArray[mid]) {
    
    
            left = mid + 1;
            // 右子数组有序,最小值在左边
            // 这里right=mid因为最小值可能就是rotateArray[mid]
        } else if (rotateArray[mid] < rotateArray[right]) {
    
    
            right = mid;
        } else {
    
    
            // 无法判断,缩小下范围
            ++left;
        }
    }
 
    return rotateArray[left];
}

console.log('minNumberInRotateArray: ', minNumberInRotateArray([3,4,5,1,2]));  // 1

11. Cut the rope (greedy)

Title description : Given a rope of length n, please cut the rope into m segments of integer length (m and n are both integers, n>1 and m>1, m<=n), the length of each rope Denote as k[1],...,k[m]. What is the maximum possible product of k[1]x...xk[m]? For example, when the length of the rope is 8, we cut it into three sections whose lengths are 2, 3, and 3 respectively, and the maximum product obtained at this time is 18.
Idea : Cutting the rope to a length of 3 can ensure that the length of the cut rope is multiplied to the maximum, but when the length of the rope is 7, cutting 3 4 is larger than 3 3*1, so when a 4 can be cut, Just cut out 4, and cut the rest into 3

function cutRope(number){
    
    
    if(number===2){
    
    
        return 1
    }
    if(number===3){
    
    
        return 2
    }
    let x=number%3; // 取出余数
    let y=parseInt(number/3); // number有多少个3
    if(x===0){
    
     // 没有余数时
        return Math.pow(3,y) // 将取出来的所有3相乘
    }else if(x===1){
    
     // 余数为1时,说明可以拿出一个3构成一个4
        return 2*2*Math.pow(3,y-1)
    }else{
    
     // 当余数为2时,直接将2乘进来即可
        return 2*Math.pow(3,y)
    }
}

12. Implement the chunk function

Problem Description : Divide an array into multiple arrays, where the number of cells in each array is determined by length. The last array may have fewer than length elements.
Example:
const a = ['a', 'b', 'c', 'd', 'e', ​​'f', 'g', 'h']; chunk(a, 4); result
:
[
[ 'a', 'b', 'c', 'd'],['e', 'f', 'g', 'h']]

function chunk(arr,size){
    
    		
    var arr1=[];		
    for(var i=0;i<arr.length;i=i+size){
    
    		 
        var arr2=arr;          
        arr1.push(arr2.slice(i,i+size));		
    }		
    return arr1;	
}

String articles:

The basics of strings :

let str = "HELLO " 
let str2 = "WORLD" 
// 字符串涉及到位置的,都是从0开始数
// const res = str.charAt(2)  // L ,返回指定位置的字符串,从0开始数
// const res = str.concat(str2)  // HELLO WORLD,返回连接好的字符串,不改变原字符串
// const res = str.indexOf('LO') // 3 返回某个字符串在原字符串中出现的第一个位置,没有就返回-1,从0开始数,区分大小写
// const res = str.includes('HEL') // true,返回布尔值,查看字符串中是否包含子串
// const res = str.replace('LO','lo') // HELlo ,将字符串替换成指定字符串,如果没找到相应字符串就返回原字符串(HELLO),返回已替换好的字符串,不改变原字符串
// 'qe.r'.replace(/\w/g, '@') //replace支持正则,将'qe.r'中的字母数字下划线都替换成@
// const res = str.slice(2,4) // LL ,将字符串按指定位置进行切片,前闭后开,slice(start, end) 
// const res = str.split('') //[ 'H', 'E', 'L', 'L', 'O', ' ' ], 将字符串分隔为字符串数组,空字符串 ("") 用作参数,那么 str中的每个字符之间都会被分割。参数的意思是从参数指定的地方分割
// const res = str.startsWith('HE') // true,查看字符串是否以指定字符串开头
// const res = str.toLowerCase(str) // hello  将字符串转为小写
// const res = str.toUpperCase(str) // HELLO 将字符串转为大写
// const res = str.trim(str) // 去除字符串两边的空格

1. Determine whether a string is a palindrome

Problem Description : Determine whether a string is a palindrome.
Solution 1. Use api : convert the string into an array (split), use the array (reverse) to rehearse the elements in the array in reverse order, and reorder the array in reverse order Converted to a string (join) and compared with the original character, equal is a palindrome, and not equal is not a palindrome.

function getRes(inputString) {
    
    
  if (typeof inputString !== 'string') {
    
    
    return false
  }
  else {
    
    
    return inputString.split('').reverse().join('') === inputString
  }
}

Solution 2, do not use api : use two pointers, one starts to move from the head, and the other starts to move from the tail, and judges whether the current position is equal every time it is moved, and returns false as long as it is not equal, and returns false when the loop is over. palindrome

function getRes(inputString) {
    
    
  if (typeof inputString !== 'string') {
    
    
    return false
  }
  let i = 0, j = inputString.length - 1
  while (i < j) {
    
    
    if (inputString[i] !== inputString[j]) {
    
    
      return false
    }
    i++
    j--
  }
  return true
}

2. The longest substring without repeated characters

Description : Given a string, find the length of the longest substring that does not contain repeated characters
Input: "abcabcbb", Output: 3
Ideas: A for loop, add the letters of the string to the third-party array in turn, before adding , to determine whether the letter already exists in the array, if not, add it directly, if there is this string, delete the array from the beginning of the array, end at the current letter position, and then add the current letter to the array , use Math.max() to keep the longest array, and finally return to max.

 if (typeof inputString !== 'string') {
    
    
    return false
  }
  let arr = [], max = 0
  for (let i = 0; i < inputString.length; i++) {
    
    
    let index = arr.indexOf(inputString[i])
    if (index !== -1) {
    
    
      arr.splice(0, index + 1)
    }
    arr.push(inputString.charAt(i))
    max = Math.max(arr.length, max)
  }
  return max
}

3. The first non-repeating number in the character stream

Problem description : Please implement a function to find the first character that appears only once in the character stream. For example, when only the first two characters "go" are read from the character stream, the first character that occurs only once is "g". When the first six characters "google" are read from this character stream, the first character that occurs only once is "l". The background will call the Insert and FirstAppearingOnce functions
in the following way : convert the string into an array, use the uniqueness of the object key, put each item of the string into the object as the key of obj, and assign the value to 0 for the first time , if it still appears for the second time or later, it is assigned a value of 1, and finally iterates through the object and outputs the key with the object value of 1.

function getRes(ch) {
    
    
  let strArr = ch.split('')
  let obj = {
    
    }
  for (let i = 0; i < strArr.length; i++) {
    
    
    if (obj[strArr[i]] === undefined) {
    
    
      obj[strArr[i]] = 0
    }
    else {
    
    
      obj[strArr[i]] = 1
    }
  }
  for (key in obj) {
    
    
    if (obj[key] === 0) {
    
    
      return key
    }
  }
  return '#'
}

4. Replace spaces

Title description : Please implement a function to replace each space in a string with "%20". For example, when the string is We Are Happy. Then the string after replacement is We%20Are%20Happy.
Idea : 1. Convert the string into an array divided by spaces, and then convert the array into a string divided by %20:

function getRes(s) {
    
    
	return s.split(" ").join("%20")
}

2. Create a new string, add the target strings to the new string one by one, and replace it with %20 when encountering spaces:

function getRes(s) {
    
    
  let newS = ''
  for (let i = 0; i < s.length; i++) {
    
    
    if (s[i] !== " ") {
    
    
      newS += s[i]
    }
    else {
    
    
      newS += '%20'
    }
  }
  return newS
}

5. Version number comparison

function toNum(a, b) {
    
    
    let aArr = a.split("")
    let bBrr = b.split("")
    let len = Math.max(a.length, b.length)
    bBrr.map((item, index, arr) => {
    
    
        if (item == '.') {
    
    
            arr.splice(index, 1)
        }
    })
    aArr.map((item, index, arr) => {
    
    
        if (item == '.') {
    
    
            arr.splice(index, 1)
        }
    })
    for (let i = 0; i < len; i++) {
    
    
        if (/[a-z]/.test(aArr[i]) && /[a-z]/.test(bBrr[i])) {
    
    
            if (aArr[i] == bBrr[i]) {
    
    
                continue
            }
            else if (aArr[i] > bBrr[i]) {
    
    
                console.log(`${
      
      a}是最新的版本`)
                return
            }
            else {
    
    
                console.log(`${
      
      b}是最新的版本`)
                return
            }
        }
        else {
    
    
            if (aArr[i] == bBrr[i]) {
    
    
                continue
            }
            else if (aArr[i] > bBrr[i]) {
    
    
                console.log(`${
      
      a}是最新的版本`)
                return
            }
            else {
    
    
                console.log(`${
      
      b}是最新的版本`)
                return
            }
        }
    }
}

var a = "v2.23a.3"; b = "v2.23b.8";

toNum(a, b);  // v2.23b.8是最新的版本

Linked list

1. Print the linked list from end to beginning

Problem description : Input a linked list and return an ArrayList in order from the end to the beginning of the linked list.
Input: {67,0,24,58}, return value: [58,24,0,67]
idea : use while loop to add the values ​​in the linked list to the array one by one, and let the pointer of the linked list go down each time you add one Move one, and finally the array calls the reverse method to output in reverse order.

function printListFromTailToHead(head)
{
    
    
	let node = head;
	let arr = []
	let i = 0
	while(node){
    
    
		arr[i] = node.val
		i++
		node = node.next
	}
	return arr.reverse()
	// 数组的倒序也可以如下:
	let resArr = []
	for(let j = 0; j < i; j++){
    
    
		resArr[j] = arr[i-j-1]
	}
}

2. Reverse linked list

Problem description : Input a linked list, after reversing the linked list, output the header of the new linked list.
Idea : We need to use three pointers to realize the reversal of the linked list. There are two important points . First, pre points to null, and both curr and next point to the first element of the linked list . Second, the order of conversion cannot be changed . 1. First use next to occupy the next element, because the next element of curr points to the previous element, and the connection with the next element is broken, and the next element can no longer be found, so it needs to occupy the space. 2. Point the next element of curr to pre (null ), after completing the pointing, move pre (pre = curr), move curr (curr = next), and finally next and curr both point to null, and pre just points to the head of the linked list

function ReverseList(pHead)
{
    
    
	let pre = null;
	let curr = pHead;
	let next = pHead
	while(curr){
    
    
		next = curr.next
		curr.next = pre
		pre = curr
		curr = next
	}
	return pre
}

3. Determine whether there is a ring in the given linked list

Idea : To determine whether there is a ring in the linked list, the key is whether the linked list can go on forever.
Then you can set two pointers, a fast pointer and a slow pointer, one for two steps and one for one step. If there are rings in the linked list, they will meet sooner or later, and the complexity is constant O(1). If the linked list is null, single node, double node, there will be no ring, just return false directly.

/*
 * function ListNode(x){
 *   this.val = x;
 *   this.next = null;
 * }
 */

/**
 * 
 * @param head ListNode类 
 * @return bool布尔型
 */
function hasCycle( head ) {
    
    
    // write code here
    let fast = head;
    let slow = head;
    while (fast!= null && fast.next != null) {
    
    
        slow = slow.next;
        fast = fast.next.next;
        if(fast === slow) {
    
    
            return true;
        }
    }
    return false;
}

tree articles

recursion

Tree algorithms generally require recursion, and recursion requires stack support. Every time a function is called, a function execution context must be created and pushed onto the stack. Take factorial as an example: when recursion satisfies the return condition, no
insert image description here
need Execute down, so factorial(0) will pop the stack, pass the result 1 to the following execution context , then execute factorial(1), pop the stack, pass the result 1 to factorial(2), and execute factorial(2) , pop the stack, and pass the result 1 to factorial(3)...
insert image description here
So recursion means not hitting the south wall and not turning back. If you hit the south wall, turn back in turn from the first hit.

0. Hump to underscore

Problem description:
let a = { aB: { aBc: 1 }, aBC: 2 }
let b = [{ aB: 1 }, { a: { aBcD: 1 } }]
is transformed into:
let a = { a_b: { a_bc : 1 }, a_b_c: 2 }
let b = [{ a_b: 1 }, { a: { a_bc_d: 1 } }]

let a = {
    
     aB: {
    
     aBc: 1 }, aBC: 2 }
let b = [{
    
     aB: 1 }, {
    
     a: {
    
     aBcD: 1 } }]

function get_(a) {
    
    
    let newobj = {
    
    }
    for (key in a) {
    
    
        if (a[key] instanceof Object) {
    
    
            newobj[key.replace(/([A-Z])/g, "_$1").toLowerCase()] = get_(a[key]) // 递归这一定要重新赋值!
        }
        else {
    
    
            newobj[key.replace(/([A-Z])/g, "_$1").toLowerCase()] = a[key] // key.replace(/([A-Z])/g, "_$1" 将key中的大写字母前加上_
        }
    }
    return newobj
}

function getRes(a) {
    
    
    let newArr = []
    if (a instanceof Object && !(a instanceof Array)) {
    
     // 注意a instanceof Object包括数组
        return get_(a) // 对象直接返回
    }
    else if(a instanceof Array) {
    
    
        for (item of a) {
    
    
            newArr.push(get_(item))
        }
        return newArr
    }
}
console.log('getRes: ', getRes(b));

1. Reconstruct the binary number

Problem Description : Input the results of the pre-order traversal and in-order traversal of a binary tree, please rebuild the binary tree. Assume that neither the input pre-order traversal nor the in-order traversal results contain duplicate numbers. For example, enter the preorder traversal sequence {1,2,4,7,3,5,6,8} and the inorder traversal sequence {4,7,2,1,5,3,8,6}, then rebuild the binary tree and return.
Idea : The first element of the pre-order traversal is the root node of the target tree. The index of the root node in the in-order traversal is obtained from the root node, and the left and right subtrees are cut out from the index in the in-order traversal. The remaining ideas are Same, recursive

console.log(reConstructBinaryTree([1, 2, 4, 7, 3, 5, 6, 8], [4, 7, 2, 1, 5, 3, 8, 6]))

function TreeNode(x) {
    
    
    this.val = x
    this.left = null
    this.right = null
}

function reConstructBinaryTree(pre, vin) {
    
    
    if (pre.length === 0 || vin.length === 0) {
    
    
        return null
    }

    let index = vin.indexOf(pre[0])

    let vinLeft = vin.slice(0, index) // 中序遍历左子树
    let vinRight = vin.slice(index + 1) // 中序遍历右子树

    let preLeft = pre.slice(1,index+1) // 先序遍历左子树
    let preRight = pre.slice(index+1) // 先序遍历右子树

    let node = new TreeNode(pre[0])
    node.left = reConstructBinaryTree(preLeft, vinLeft)
    node.right = reConstructBinaryTree(preRight, vinRight)
    return node
}

2. The next node of the binary tree

Problem description : Given a node in a binary tree, please find the next node in the inorder traversal order and return it. Note that the nodes in the tree not only contain the left and right child nodes, but also contain the next pointer pointing to the parent node
insert image description here

Ideas : 1. If there is a right subtree, then the next node is the leftmost point of the right subtree; (eg: D, B, E, A, C, G) 2. If there is no right subtree, it can also be divided into Two types, a) is the left child of the parent node (eg: N, I, L), then the parent node is the next node; b) is the right child of the parent node (eg: H, J, K, M) to find him Parent's parent's parent's parent...until the current node is the left child of its parent. If there is no eg: M, then he is the tail node.

function TreeLinkNode(x) {
    
    
    this.val = x;
    this.left = null;
    this.right = null;
    this.next = null;
}
function GetNext(pNode) {
    
    
    // // write code here
    if(pNode == null) return pNode;
    if(pNode.right !== null){
    
    
        //如果有右子树
        pNode = pNode.right;
        while(pNode.left != null){
    
    
            pNode = pNode.left;
        }
        return pNode;
    }
    while(pNode.next !== null){
    
    
        if(pNode === pNode.next.left){
    
    
        // 2.1 该节点为父节点的左子节点,则下一个节点为其父节点
            return pNode.next;
        }
       // 2.2 该节点为父节点的右子节点,则沿着父节点向上遍历,知道找到一个节点的父节点的左子节点为该节点,则该节点的父节点下一个节点
        pNode = pNode.next;
    }
    return null;
    }

3. Post-order traversal of binary search tree

Title description: Input an array of integers, and judge whether the array is the result of post-order traversal of a binary search tree. If yes, output true, otherwise output false. Assume that any two numbers in the input array are different from each other. For example, input [4,8,6,12,16,14,10] output: true; input [7,4,6,5] output: false
Idea: the last element in the post-order traversal of the binary search tree must be The root node of the tree, we find the first element larger than it in the array, the left side of this element must be its left subtree, and the right side is its right subtree, and each element in the left subtree must be larger than the root node Small, each element in the right subtree must be larger than the root node. Once one of these two conditions is not satisfied, return false. The same is true for the left subtree. The last element of the left subtree must be the left subtree root node, and need to find the first element larger than it in the left subtree, the left side of the element must be its left subtree, and the right side is its right subtree... the same is true for the right subtree, so we use recursion to solve .

function getRes(arr) {
    
    
    if (arr <= 1) {
    
    
        return true
    }

    let rootItem = arr[arr.length - 1] // 找到中序遍历的根节点
    let index = 0, leftRoot, rightRoot, leftTree, rightTree, res = true

    for (let i = 0; i < arr.length; i++) {
    
    
        if (arr[i] > rootItem) {
    
     // 找到第一个比根节点大的值,用它的切出左右子树
            index = arr[i] 
            break
        }
    }

    leftRoot = arr.indexOf(index) - 1 // 左子树的根节点
    rightRoot = arr[arr.length - 2] // 右子树的根节点
    leftTree = arr.slice(0, leftRoot + 1)  // 根据根节点切出左子树
    rightTree = arr.slice(leftRoot + 1, arr.length - 1) // 根据根节点切出右子树

    if (leftTree.length > 0) {
    
     
        for (let i = 0; i < leftTree.length; i++) {
    
    
            if (leftTree[i] > rootItem) {
    
     // 查看是否左子树中的每个值都比根节点小,比根节点大就不满足条件,return false
                res = false
            }
        }
    }
    if (rightTree.length > 0) {
    
    
        for (let i = 0; i < rightTree.length; i++) {
    
    
            if (rightTree[i] < rootItem) {
    
     // 查看是否右子树中的每个值都比根节点大,比根节点小就不满足条件,return false
                res = false
            }
        }
    }
    getRes(leftTree) // 递归切出来的左子树
    getRes(rightTree) // 递归切出来的右子树
    return res
}

console.log('getRes(ch): ', getRes([4, 8, 6, 12, 16, 14, 10]));  // true

level traversal of binary tree

Description of the problem: As shown in the figure, it is the hierarchical traversal of the binary tree, that is, according to the direction pointed by the arrow, according to the hierarchical order of 1, 2, 3, and 4, access each node in the binary tree. Recursive solution
insert image description here
:

var levelOrder = function(root) {
    
    
  if(!root)return []
  let res=[]
  let aux=[root]
  while(aux.length>0){
    
    
    let len=aux.length
    let vals=[]
    for(let i=0;i<len;i++){
    
    
      let node=aux.shift()
      vals.push(node.val)
      if(node.left)aux.push(node.left)
      if(node.right)aux.push(node.right)
    }
    res.push(vals)
  }
  return res
};

Non-recursive solution:

var levelOrder = function(root) {
    
    
  if(!root)return []
  let res=[]
  let aux=[root]
  while(aux.length>0){
    
    
    let len=aux.length
    let vals=[]
    for(let i=0;i<len;i++){
    
    
      let node=aux.shift()
      vals.push(node.val)
      if(node.left)aux.push(node.left)
      if(node.right)aux.push(node.right)
    }
    res.push(vals)
  }
  return res
};

Stack

1. Two stacks implement queues

Title description : Use two stacks to implement a queue, respectively complete the functions of inserting an integer (push) at the end of the queue and deleting an integer (pop) at the head of the queue. The elements in the queue are of type int. Ensure that the operation is legal, that is, ensure that there are elements in the queue when the pop operation is performed.
Idea : stack first in first out, queue first in first out, two stacks stack1, stack2, stack1 is used to push into the stack, stack2 is used to pop out the stack, the elements in stack2 come from the elements popped up by stack1, as long as there are elements in stack2 , Let stack2 pop the stack every time it is requested to pop the stack , and stack2 will pop the stack from stack1 when there are no elements.

let stack1 =[]
let stack2 = []

function push(node) {
    
    
     // write code here
    stack1.push(node)
}
function pop() {
    
    
     // write code here
    if (stack1.length==0 && stack2.length==0) {
    
    
        return null
    }
    else if(stack2.length){
    
    
        return stack2.pop() 
    }
    else{
    
    
        while(stack1.length){
    
    
            stack2.push(stack1.pop())
        }
    }
    return stack2.pop()
}

Search articles

1. Search in order

It is a general for loop search, time complexity O(n)

function sequenceSearch(arr, num) {
    
    
    const len = arr.length
    for (let i = 0; i < len; i++) {
    
    
        if(arr[i] == num){
    
    
            return i
        }
    }
    return null
}
console.log(sequenceSearch([1,4,7,9],7))  // 2

2. Binary search

Idea : left and right point to the first and last elements of the array respectively, mid points to the middle element, when the target is smaller than the middle element, right = mid+1, when the target is greater than the middle element, left = mid+1, when the middle element = target, return target, the three conditions are not met, indicating that there is no such element in the array, and return undefined
Every search, the range will be reduced to half of the previous one, and the time complexity is O(logn)

function getRes(rotateArray, target) {
    
    
  let len = rotateArray.length
  let left = 0
  let right = len - 1
  while (left <= right) {
    
    
    let mid = Math.floor((left + right) / 2)
    if (target > rotateArray[mid]) {
    
    
      left = mid + 1
    }
    else if (target < rotateArray[mid]) {
    
    
      right = mid - 1
    }
    else if (target = rotateArray[mid]) {
    
    
      return mid
    }
    else {
    
    
      return undefined
    }
  }
}

3. Hash table lookup

Topic: For the first non-repeating number in the character stream,
see the third question in the above string chapter for details

4. Binary sort tree search

The data structure corresponding to the binary sorting tree search algorithm is a binary search tree. For an example of the algorithm, see the third question of the tree above.

Sorting

1. Bubble sort

Time complexity: average time complexity O(n n), best case O(n), worst case O(n n)
space complexity: O(1)
stability: stable

function swap(i,j,arr){
    
    
    let temp = 0
    temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
}

function bubbleSort(arr) {
    
    
    let len = arr.length
    for (let i = 0; i < len; i++) {
    
    
        for (let j = i + 1; j < len; j++) {
    
    
            if (arr[i] > arr[j]) {
    
    
                swap(i,j,arr)
            }
        }
    }
    return arr
}
console.log(bubbleSort([5, 2, 7, 9, 1])) // [ 1, 2, 5, 7, 9 ]

2. Insertion sort

Insertion sorting (take out the elements in the array in turn, compare the taken out elements with the elements that have been arranged in the previous order one by one, and compare them further when encountering an element that is larger than it, until it encounters an element that is smaller than him, then Insert the current element into the front)
space of the first element he encounters that is smaller than him : it only needs an auxiliary space for a record, so the key depends on the time complexity.
The best case : that is, the sorting table itself is ordered , and only n-1 comparisons are required. Since arr[i] > arr[i+1] each time, no records are moved, and the time complexity is O (n) .
Worst case : It is the reverse order of the sorting table , which needs to compare (n+2)(n-1)/2 times and move (n+4)(n-1)/2 times. If the sorting records are random, according to the principle of the same probability, the average number of comparisons and moves is about O(n²)/4 times.
The time complexity is O(n²) , which is better than bubble sort and simple selection sort algorithm.

function insertSort(arr) {
    
    
    let len = arr.length
    for (let i = 1; i < len; i++) {
    
    
        let currentValue = arr[i] // 获取数组中的当前元素
        let j = i - 1 // 指到当前元素的前一个元素
        while (j >= 0 && arr[j] > currentValue) {
    
     // 当前一个元素大于当前元素时
            if (arr[j] >= currentValue) {
    
     // 如果前一个元素大于当前元素
                arr[j + 1] = arr[j] // 将前一个元素往后移一位,因为当前元素本来就被currentValue保存下来了,i的位置基本可以认为是空的
            }
            j--
        }
        arr[j + 1] = currentValue // while循环结束,j指到比当前元素小的位置,我们就把当前元素插到它的前面
    }
    return arr
}

console.log('insertSort(ch): ', insertSort([4, 8, 6, 12, 16, 4, 14, 10])); //  [  4,  4,  6,  8, 10, 12, 14, 16]

3. Quick Sort

Quick sorting (and in the worst case, that is, when the array is already ordered or roughly ordered, each division is based on the last element of the array as the standard, and each division can only reduce one element, and quick sorting will unfortunately degenerate For bubble sorting, the worst case is O(n²).Quick sorting is the same as merge sorting, the total time complexity of each layer is O(n), because each element needs to be traversed once.In practical applications, The average time complexity of quick sorting is O(nlogn). Space complexity: the recursive algorithm of quick sorting requires the support of the stack, and the size of the stack is at most n, so it is O(n))
. The length of a subinterval is twice that of the previous one, so merge_sort recursion needs to be executed logn times
Key point 2: For each interval, when processing, it is necessary to traverse each element in the interval once, and the total time of each layer is complex Degrees are all O(n)

function quickSort(arr) {
    
    
    if (arr.length <= 1) {
    
     // 如果数组中只有一个值或者是空数组,直接将其返回,这是递归的条件
        return arr
    }
    let currentIndex = Math.floor(arr.length / 2) // 获取数组最中间的数
    let currentItem = arr.splice(currentIndex, 1) // 将最中间的数取出并在数组中将最中间的数删除
    let leftArr = [], rightArr = [] 
   // 关键点2:对于每一个区间,处理的时候,都需要遍历一次区间中的每一个元素,每一层的总时间复杂度都是O(n)
    arr.forEach(item => {
    
    
        if (item < currentItem) {
    
    
            leftArr.push(item) // 将数组中比中间值小的都放在中间值的左边
        }
        else {
    
    
            rightArr.push(item) // 将数组中比中间值大的都放在中间值的左边
        }
    })

    // 左数组和右数组操作一样,递归再进行上面的部分
    return quickSort(leftArr).concat(currentItem).concat(quickSort(rightArr))
    // 关键点1:划分子区间,每一次的子区间长度是上一次的两倍,所以merge_sort递归需要执行logn次
}

console.log(quickSort([5, 2, 7, 9, 1]))  // [ 1, 2, 5, 7, 9 ]

4. Merge sort

First divide the array into two and one into two...until there is only one element in an array, then put the elements into an array after comparing the elements, pass the recursive feature to the next recursive function, and finally merge the average time is
complicated Degree: O(nlogn)
Best Time Complexity: O(n)
Worst Time Complexity: O(nlogn)
Space Complexity: O(n)
Sorting Method: In-place
Stability: Stable

function merge_sort(arr) {
    
     // 将数组由最中间的数作为基准一分为二,递归执行,最终将一个大数组分为由一个元素组成的数组
    if (arr.length == 1){
    
    
         return arr
    }
    
    var mid = Math.floor(arr.length / 2)
    var leftArr = arr.slice(0, mid)
    var rightArr = arr.slice(mid)
// 关键点1:划分子区间,每一次的子区间长度是上一次的两倍,所以merge_sort递归需要执行logn次
    return Merger(merge_sort(leftArr), merge_sort(rightArr)); //合并左右部分
    // 关键点2:Merger方法每次执行的时间复杂度为O(n),具体看下方
}

function Merger(leftArr, rightArr) {
    
    
    var leftLen = leftArr && leftArr.length;
    var rightLen = rightArr && rightArr.length;
    var resArr = [];
    var i = 0, j = 0;

    while (i < leftLen && j < rightLen) {
    
    
        if (leftArr[i] < rightArr[j]) {
    
    
            resArr.push(leftArr[i++]);
        }
        else {
    
    
            resArr.push(rightArr[j++]);
        }
    }
    while (i < leftLen) {
    
    
        resArr.push(leftArr[i++]);

    }
    while (j < rightLen) {
    
    
        resArr.push(rightArr[j++]);
    }
    console.log("将数组", leftArr, '和', rightArr, '合并为', resArr)
    return resArr;
    递归过程:
    // 将数组 [ 8 ] 和 [ 2 ] 合并为 [ 2, 8 ]
    // 将数组 [ 1 ] 和 [ 2, 8 ] 合并为 [ 1, 2, 8 ]
    // 将数组 [ 4 ] 和 [ 9 ] 合并为 [ 4, 9 ]
    // 将数组 [ 6 ] 和 [ 4, 9 ] 合并为 [ 4, 6, 9 ]
    // 将数组 [ 1, 2, 8 ] 和 [ 4, 6, 9 ] 合并为 [ 1, 2, 4, 6, 8, 9 ]
}
console.log('merge_sort(ch): ', merge_sort([1,8,2,6,4,9])); //  [  4,  4,  6,  8, 10, 12, 14, 16]

Backtracking Algorithms

1. The path in the matrix

Description of the problem : Please design a function to determine whether there is a path containing all the characters of a string in a matrix. The path can start from any grid in the matrix, and each step can move one grid to the left, right, up, and down in the matrix. If a path passes through a grid in the matrix, the path cannot enter the grid again. [[a,b,c,e],[s,f,c,s],[a,d,e,e]], "abcced" idea: choose a location as the starting point of the path, choose
( 0 , 0), each of the following steps can move one space up, right, down, and left in the matrix. If you can’t find it, return false. If you find it, set the corresponding position of the Boolean value matrix to true. Start up, right, down, and left; after moving, you need to make boundary judgments: 1. Determine whether the position is still in the matrix; 2. Whether it has been passed; when the corresponding number in the string is found, in the matrix It can move one space up, right, down, and left to find the next character that matches the target string. The operation method of moving is the same, so here we use recursion to implement, and the path can be regarded as a Stack, because repeated paths cannot be added to the grid repeatedly, so it is also necessary to define a Boolean value matrix with the same size as the character matrix to identify whether the path has entered each grid.

// [[a,b,c,e],[s,f,c,s],[a,d,e,e]],"abcced"
let m, n // m行 n列
let p = [[-1, 0], [1, 0], [0, 1], [0, -1]] // 向左 右 下 上 的方向走
let isUsed // 判断格子是否被走过,走过就为true,没走过为false
function hasPath(matrix, word) {
    
    
    m = matrix.length
    n = matrix[0].length
    isUsed = new Array(m).fill(false).map(p => new Array(n).fill(false)) // 创建一个m行 n列的矩阵
    // 从[0,0]开始找, 循环多次找到首个字母的初始位置
    for (let i = 0; i < m; i++) {
    
    
        for (let j = 0; j < n; j++) {
    
    
            if (findWords(matrix, word, 0, i, j)) {
    
    
                return true
            }
        }
    }
    return false;
}

function findWords(matrix, word, index, startX, startY) {
    
    
    if (index === word.length - 1) {
    
    
        return matrix[startX][startY]  === word[index]
    }

    if (matrix[startX][startY]  == word[index]) {
    
     // 在矩阵中找到了words中的字母
        isUsed[startX][startY] = true // 表明这个格子已经找过了
        for (let i = 0; i < 4; i++) {
    
      // 从矩阵中已经找到words中的字母的位置开始从左 右 上 下的方向又开始寻找words中的下一个字母
            let nextX = startX + p[i][0] 
            let nextY = startY + p[i][1]
            if (isInArea(nextX, nextY) && !isUsed[nextX][nextY]) {
    
     // 判断是否走超出了格子 && 判断这个格子是否被走过
                if(findWords(matrix, word, index+1, nextX, nextY)){
    
     // index+1 因为index的位置的words字母已经被找到了,相同的方法比较矩阵中值和words中的字母是否相同
                    return true
                }
            }
        }
    }
    isUsed[startX][startY] = false
    return false // 在矩阵中没找到与words中相同的值就return false
}

function isInArea(x, y) {
    
    
    return x >= 0 && y >= 0 && x < m && y < n
}

console.log('hasPath: ', hasPath([
    ['a', 'b', 'c', 'e'],
    ['s', 'f', 'c', 's'],
    ['a', 'd', 'e', 'e']], "abcced"));
// true

2. The range of motion of the robot

On the ground there is a square with rows and cols. The coordinates are from [0,0] to [rows-1,cols-1]. A robot starts to move from the grid with coordinates 0 and 0, and can only move one grid in the four directions of left, right, up, and down at a time, but cannot enter the grid where the sum of the digits of the row coordinates and column coordinates is greater than the threshold. For example, when the threshold is 18, the robot can enter square [35,37], because 3+5+3+7 = 18. However, it cannot enter square [35,38] because 3+5+3+8 = 19. How many grids can the robot reach?
Idea : let the robot start walking from 0,0 position, its next step can go up, down, left, right, but before it goes down, we need to judge; 1. Its current position is within the matrix 2 , Whether the matrix grid where it is located satisfies that the sum of the digits of the row coordinates and column coordinates is greater than the threshold; 3. Whether it has already passed through the grid , the last condition we can create a matrix of rows and cols columns, and put it in the beginning They are all false, when a cell of it is passed, we set that cell to true, so true means it has been passed.

function movingCount(threshold, rows, cols) {
    
    
    if (threshold < 0 || rows < 0 || cols < 0) {
    
    
        return 0
    }
    let isVisited = new Array(rows).fill(false).map(item => new Array(cols).fill(false))
    let count = movingCountCore(threshold, rows, cols, 0, 0, isVisited)
    return count
}

function movingCountCore(threshold, rows, cols, startX, startY, isVisited) {
    
    
    let count = 0
    if (checkBoard(rows, cols, startX, startY) && getDigitSum(startX, startY) <= threshold && !isVisited[startX][startY]) {
    
    
        isVisited[startX][startY] = true
        count = 1 + movingCountCore(threshold, rows, cols, startX - 1, startY, isVisited)
            + movingCountCore(threshold, rows, cols, startX, startY - 1, isVisited)
            + movingCountCore(threshold, rows, cols, startX + 1, startY, isVisited)
            + movingCountCore(threshold, rows, cols, startX, startY + 1, isVisited)
    }
    return count
}

function checkBoard(rows, cols, startX, startY) {
    
    
    if (startX >= 0 && startX < rows && startY >= 0 && startY < cols) {
    
    
        return true
    }
    return false
}

function getDigitSum(startX, startY) {
    
    
    let sum = 0
    let str = startX + '' + startY
    for (let i = 0; i < str.length; i++) {
    
    
        sum += str.charAt(i) / 1
    }
    return sum
}
console.log(movingCount(5, 10, 10)); // 21

High-quality code articles

1. The integer power of the value

Title description : Given a floating-point number base of type double and an integer exponent of type int. Find the exponent power of base. Make sure base and exponent are not 0 at the same time. Library functions are not allowed, and there is no need to consider large numbers or the number of 0s after the decimal point.
Note : Although this question is simple, it is often a simple question that cannot be taken lightly. The complete boundary judgment must be considered. Integers, negative numbers and zeros must be taken into account. Simple questions that do not consider the boundary will have a bad impact on the interviewer.

function Power(base, exponent) {
    
    
    if (base === 0) {
    
    
        return 0
    }
    else if (exponent === 0) {
    
    
        return 1
    }
    else {
    
    
        let index = 0
        let res = 1
        let numType = true
        if (exponent < 0) {
    
    
            numType = false
            exponent = -exponent
        }
        while (index < exponent) {
    
    
            res *= base
            index++
        }
        return numType ? res : 1 / res
    }
}
console.log('Power: ', Power(2, 3)); // 8 

The code words are not easy, they are all summed up by myself, please like and encourage~
Continuously updating...

Guess you like

Origin blog.csdn.net/xiaoguoyangguang/article/details/117334087