join us!
Mountain" , to provide front-end developers with technical information and a series of basic articles. For a better user experience, please move to our official website novices (1612c57cbe7bd0 https://xhs-rookies.com/ ) to learn and get the latest articles in time.
"Code tailor" , if you are interested in our article or want to make some suggestions, follow "Novices of Xiaohe Mountain" public account, contact us, you can also watch it on WeChat Our article. Every suggestion or approval is a great encouragement to us!
Interview series are updated from time to time, please stay tuned
Preface
This column focuses on explaining the interview handwritten procedural questions/algorithmic questions in the interview.
Note: This column will only involve key content and will not be expanded. For some topics that need to expand knowledge points, we will place the expanded content and overall detailed information at the top of each topic, and you can check it by yourself.
Handwritten program questions/algorithm questions
Handwritten program questions/algorithm questions |
---|
Program output topic: the attribute problem between the constructor and the instance object |
Program programming questions: flat, flatten the array, realize the effect of flattening the array by yourself |
Programming problem: Realize promise all by yourself |
Program programming problem: implement reducer by yourself |
Programming problem: URL parsing into objects |
Programming problem: use setTimeout to write a setInterval |
Algorithmic question: the problem of the largest substring without repeated characters |
Algorithmic problem: traversing the front, middle and back of the binary tree |
Algorithm problem: maze problem |
Algorithm question: handwritten bubble sort |
Algorithmic problem: the inversion of an incomplete binary tree |
Problem analysis
Attribute problem between constructor and instance object
What does the following code output?
function Otaku() {
this.b = 1
this.c = 2
}
var person = new Otaku()
Otaku.prototype.b = 4
person.c = 5
console.log('1:', person.b)
console.log('2:', person.c)
person.__proto__.b = 10
console.log('3:', person.b)
console.log('4:', Otaku.prototype.b)
This topic involves the knowledge points between the constructor and the instance object. It also involves the problem of prototype and prototype chain. For details, see JavaScript in-depth from prototype to prototype chain .
Let's reveal the answer first:
1: 1
2: 5
3: 1
4: 10
Did you answer all of them correctly? Let's take a look at this problem together. This question first gave a constructor Otaku
, this constructor has two attributes b
and c
, and then use new to create its instance object person
, if you know the prototype, then you must know that the instance object person
has obtained the constructor Properties in.
function Otaku() {
this.b = 1
this.c = 2
}
var person = new Otaku() // person.b = 1; person.c = 2
Seeing this you will find that the constructor Otaku
has an attribute prototype
. The prototype
attribute of this constructor points to an object, which is instance created by calling the constructor, which is the prototype of this example of person
. That is to say, Otaku.prototype.b = 4;
the statement b
actually points to the b of the prototype.
function Otaku() {
this.b = 1
this.c = 2
}
var person = new Otaku()
Otaku.prototype.b = 4 // 修改的是 person 的原型的属性 b
person.c = 5 // 修改的是 person 的 c
console.log('1:', person.b) // person.b = 1
console.log('2:', person.c) // person.c = 5
See here, we also found person
property __proto__
, this property also point person
prototype, so this sentence b
property is also pointing to the prototype b
function Otaku() {
this.b = 1
this.c = 2
}
var person = new Otaku() // person.b = 1; person.c = 2
Otaku.prototype.b = 4 // 修改的是 person 的原型的属性 b
person.c = 5 // 修改的是 person 的 c
console.log('1:', person.b) // person.b = 1
console.log('2:', person.c) // person.c = 5
person.__proto__.b = 10 // 修改的事 preson 的原型的属性b
console.log('3:', person.b) // person.b = 1
console.log('4:', Otaku.prototype.b) // Otaku.prototype.b = 10
This is the result. Regarding the knowledge points involved in this question, the focus is still on the prototype and the prototype chain.
Programming questions
1. Flat, flatten the array, realize the effect of flattening the array by yourself
Here are only two relatively simple implementations, and later will involve the use of reduce
and stacks, the use of Generator
, the prototype chain, etc. For details, see: Interviewer's series of questions: Array flattening (flattening) flat method implementation-Zhihu (zhihu.com) ")
- The simplest traversal implementation
const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, 'string', { name: '弹铁蛋同学' }]
// concat + 递归
function flat(arr) {
let arrResult = []
arr.forEach((item) => {
if (Array.isArray(item)) {
arrResult = arrResult.concat(flat(item)) // 递归
// 或者用扩展运算符
// arrResult.push(...arguments.callee(item));
} else {
arrResult.push(item)
}
})
return arrResult
}
flat(arr)
// [1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 3, 5, "string", { name: "弹铁蛋同学" }];
- Pass in the array to control the number of recursive layers
// reduce + 递归
function flat(arr, num = 1) {
return num > 0
? arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? flat(cur, num - 1) : cur), [])
: arr.slice()
}
const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, 'string', { name: '弹铁蛋同学' }]
flat(arr, Infinity)
// [1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 3, 5, "string", { name: "弹铁蛋同学" }];
2. Realize promise all by yourself
Promise.newAll = function (promiseArr) {
let results = []
return new Promise((reslove, reject) => {
promiseArr.forEach((item_promise) => {
item_promise.then((res) => results.push(res)).catch((err) => reject(err))
})
return reslove(results)
})
}
3. Implement the reducer yourself
Note: Arrow functions cannot be used. The absence of this in the arrow function will cause sourcearr to be an empty object
Array.prototype.fakereduce = function (fn, initnumber = 0) {
let sum_increase = initnumber
let sourcearr = this
for (let i = 0; i < sourcearr.length; i++) {
sum_increase = fn(sum_increase, sourcearr[i])
}
return sum_increase
}
This is only the most basic, only contains the first two parameters, and does not check whether it is a function. (Add the judgment below)
// 判断调用对象是否为数组
if (Object.prototype.toString.call([]) !== '[object Array]') {
throw new TypeError('not a array')
}
// 判断调用数组是否为空数组
const sourceArray = this
if (sourceArray.length === 0) {
throw new TypeError('empty array')
}
// 判断传入的第一个参数是否为函数
if (typeof fn !== 'function') {
throw new TypeError(`${fn} is not a function`)
}
4. URL parsing to objects
Convert the URL entered below into an object:
http://www.baidu.com/s?wd=春节&name=justin
{
wd: '春节',
name: 'justin'
}
The focus of this question is segmentation. ?
and place them in the object. Different key-value pairs are segmented &
The specific code is as follows (only one solution is given here):
let urlToJson = (url = window.location.href) => {
// 箭头函数默认传值为当前页面url
url = url.encodeURIComponent()
let obj = {},
index = url.indexOf('?'),
params = url.substr(index + 1)
if (index != -1) {
let parr = params.split('&')
for (let i of parr) {
let arr = i.split('=')
obj[arr[0]] = arr[1]
}
}
return obj
}
5. Use setTimeout to write a setInterval
extension: uses setInterval
implement a setTimeout
const mySetInterval = (callback, time) => {
;(function inner() {
const timer = setTimeout(() => {
callback()
clearTimeout(timer)
inner()
}, time)
})()
}
Algorithm question
1. The problem of the largest substring without repeated characters
For details, please see: 3. The longest substring without repeated characters-LeetCode (leetcode-cn.com) ")
There are roughly two methods: brute force traversal, sliding window
The sliding window code is given here. For detailed explanation, please see the analysis of leetcode
var lengthOfLongestSubstring = function (s) {
// 哈希集合,记录每个字符是否出现过
const occ = new Set()
const n = s.length
// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
let rk = -1,
ans = 0
for (let i = 0; i < n; ++i) {
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.delete(s.charAt(i - 1))
}
while (rk + 1 < n && !occ.has(s.charAt(rk + 1))) {
// 不断地移动右指针
occ.add(s.charAt(rk + 1))
++rk
}
// 第 i 到 rk 个字符是一个极长的无重复字符子串
ans = Math.max(ans, rk - i + 1)
}
return ans
}
2. The front, middle and back traversal of the binary tree
The binary tree structure is as follows:
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
There are many traversal methods, and we use the recursive method here.
preorder traversal:
function preOrderReducer(head) {
if (head === null) {
return
}
console.log(head.val)
preOrderReducer(head.left)
preOrderReducer(head.right)
}
In-order traversal
function preOrderReducer(head) {
if (head === null) {
return
}
preOrderReducer(head.left)
console.log(head.val)
preOrderReducer(head.right)
}
post-order traversal
function preOrderReducer(head) {
if (head === null) {
return
}
preOrderReducer(head.left)
preOrderReducer(head.right)
console.log(head.val)
}
3. Maze problem
Title Description:
In a n
* m
, the starting point is [0, 0] and the ending point is [n -1, m -1]. Now you need to judge whether the maze has at least one path. If there is a path, it returns true
, otherwise it returns false
.
n
* m
There may be a wall in the maze. If the current position is 1, it means that the current position is a wall and you cannot walk.
input: n, m, maze (array)
output: true
/ false
For example:
input: 3 3 [ [0,1,1],[0,0,0],[0,1,0] ]
output: true
title analysis:
Generally speaking, DFS
BFS
, 0612c57cbe86be or dynamic programming can be solved, and the solutions are very diverse. There are many variants of this problem, such as output paths and so on.
Sample code:
// BFS
const findMazeWay = (n, m, maze) => {
if (maze[(0, 0)] === 1) {
//如果起点为墙壁则直接无解
return false
} else {
return dfsSearch(0, 0, maze)
}
function dfsSearch(index_n, index_m, maze) {
maze[index_n][index_m] = -1 //走过的路判定为-1
if (index_n === n - 1 && index_m === m - 1) {
return true
}
if (index_m + 1 <= m - 1 && maze[index_n][index_m + 1] === 0)
dfsSearch(index_n, index_m + 1, maze)
if (index_n + 1 <= n - 1 && maze[index_n + 1][index_m] === 0)
dfsSearch(index_n + 1, index_m, maze)
if (index_m - 1 >= 0 && maze[index_n][index_m - 1] === 0) dfsSearch(index_n, index_m - 1, maze)
if (index_n - 1 >= 0 && maze[index_n - 1][index_m] === 0) dfsSearch(index_n - 1, index_m, maze)
}
}
console.log(
findMazeWay(3, 3, [
[0, 1, 1],
[0, 0, 1],
[1, 0, 0],
]),
)
Problem expansion: If successful, please output at least one successful path. (Or output all successful paths)
4. Handwritten bubble sort
sample code:
function mySort(arr) {
for (let i = 0; i < arr.length - 1; i++) {
for (let j = i; j < arr.length; j++) {
if (arr[i] > arr[j]) {
let temp = arr[j]
arr[j] = arr[i]
arr[i] = temp
}
}
}
}
5. The inversion of an incomplete binary tree
Title description:
Assuming there is a binary tree of trees, we need to transform all its left subtrees into right subtrees. (For each child node, conversion is required)
The tree structure is as follows:
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
title analysis:
The point of this question is to traverse the tree, and in the case of traversal, two subtrees need to be exchanged, so the depth traversal of DFS
There are many traversal methods, and the solution given here is one of them.
sample code:
const treeReBuild(tree: TreeNode){
if(tree === null){
return
}
let temp = tree.right
tree.right = tree.left
tree.left = temp
treeReBuild(tree.left)
treeReBuild(tree.right)
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。