目录
obj[item.id] = { ...item, children: [] }
obj[pid].children.push(treeitem)
toString/join(',').split(',').map(Number)
动态规划(Dynamic Programming,DP) 最值选择+重叠子问题
到达last element的最小跳跃次数,nums[i]最远可以跳跃的步数
数组
前缀和、差分数组
双指针(快慢指针)
单调栈、单调队列:(单调递增/减)下/上一个更大/小元素
二叉树
数组和树
扁平结构(一维数组)转树
obj[item.id] = { ...item, children: [] }
pid === 0
!obj[pid]
obj[pid].children.push(treeitem)
//pid:parent id
let arr = [
{ id: 1, name: '部门1', pid: 0 },
{ id: 2, name: '部门2', pid: 1 },
{ id: 3, name: '部门3', pid: 1 },
{ id: 4, name: '部门4', pid: 3 },
{ id: 5, name: '部门5', pid: 4 },
]
// // 上面的数据转换为 下面的 tree 数据
// [
// {
// "id": 1,
// "name": "部门1",
// "pid": 0,
// "children": [
// {
// "id": 2,
// "name": "部门2",
// "pid": 1,
// "children": []
// },
// {
// "id": 3,
// "name": "部门3",
// "pid": 1,
// "children": [
// {
// id: 4,
// name: '部门4',
// pid: 3,
// "children": [
// {
// id: 5,
// name: '部门5',
// pid: 4,
// "children": []
// },
// ]
// },
// ]
// }
// ]
// }
// ]
function tree(items) {
// 1、声明一个数组和一个对象 用来存储数据
let arr = []
let obj = {}
// 2、给每条item添加children ,并连带一起放在obj对象里
for (let item of items) {
obj[item.id] = { ...item, children: [] }
}
// 3、for of 逻辑处理
for (let item of items) {
// 4、把数据里面的id 取出来赋值 方便下一步的操作
let id = item.id
let pid = item.pid
// 5、根据 id 将 obj 里面的每一项数据取出来
let treeitem = obj[id]
// 6、如果是第一项的话 吧treeitem 放到 arr 数组当中
if (pid === 0) {
// 把数据放到 arr 数组里面
arr.push(treeitem)
} else {
// 如果没有 pid 找不到 就开一个 obj { }
if (!obj[pid]) {
obj = {
children: []
}
}
// 否则给它的 obj 根基 pid(自己定义的下标) 进行查找 它里面的children属性 然后push
obj[pid].children.push(treeitem)
}
}
// 返回处理好的数据
return arr
}
console.log(tree(arr))
数组扁平化
toString/join(',').split(',').map(Number)
要求将数组参数中的多维数组扩展为一维数组并返回该数组。
数组参数中仅包含数组类型和数字类型
function flatten(arr){
// toString() + split() 实现
return arr.toString().split(',').map(item => Number(item));
//join() + split() 实现
return arr.join(',').split(',').map(item => Number(item));
//reduce 实现
return arr.reduce((target, item) => {
return target.concat(Array.isArray(item) ? flatten(item) : item);
}, [])
// 递归实现
let res = [];
arr.forEach(item => {
if (Array.isArray(item)) {
res = res.concat(flatten(item))
} else {
res.push(item);
}
});
return res;
// 扩展运算符实现
while(arr.some(item => Array.isArray(item))){
arr = [].concat(...arr);
}
return arr;
// flat()实现(这里不支持使用)
return arr.flat(Infinity);
}
排序
快速排序
快速排序的基本思想是通过分治来使一部分均比另一部分小(大)再使两部分重复该步骤而实现有序的排列。核心步骤有:
- 选择一个基准值(pivot)
- 以基准值将数组分割为两部分
- 递归分割之后的数组直到数组为空或只有一个元素为止
key:
- pivot = array.splice(pivotIndex, 1)[0]
- _quickSort(left).concat([pivot], _quickSort(right))
const _quickSort = array => {
if(array.length <= 1) return array
var pivotIndex = Math.floor(array.length / 2)
var pivot = array.splice(pivotIndex, 1)[0]
var left = []
var right = []
for (var i=0 ; i<array.length ; i++){
if (array[i] < pivot) {
left.push(array[i])
} else {
right.push(array[i])
}
}
return _quickSort(left).concat([pivot], _quickSort(right))
}
BFS:最短路径
BFS 找到的路径一定是最短的,但代价就是空间复杂度可能比 DFS 大很多
回溯O(N!):选择/DFS
运算:栈
动态规划(Dynamic Programming,DP) 最值选择+重叠子问题
输入(i,j,w):for(i,j){w}
数组
折半 / 二分查找
判定树:描述 折半查找过程
ASLsucc≈log2(n+1)-1
keys: [L,R] while(L<=R)
螺旋矩阵*
/**
* @param {number} n
* @return {number[][]}
*/
var generateMatrix = function(n) {
let startX = startY = 0; // 起始位置
let loop = Math.floor(n/2); // 旋转圈数
let mid = Math.floor(n/2); // 中间位置
let offset = 1; // 控制每一层填充元素个数
let count = 1; // 更新填充数字
let res = new Array(n).fill(0).map(() => new Array(n).fill(0));
while (loop--) {
let row = startX, col = startY;
// 上行从左到右(左闭右开)
for (; col < startY + n - offset; col++) {
res[row][col] = count++;
}
// 右列从上到下(左闭右开)
for (; row < startX + n - offset; row++) {
res[row][col] = count++;
}
// 下行从右到左(左闭右开)
for (; col > startY; col--) {
res[row][col] = count++;
}
// 左列做下到上(左闭右开)
for (; row > startX; row--) {
res[row][col] = count++;
}
// 更新起始位置
startX++;
startY++;
// 更新offset
offset += 2;
}
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
if (n % 2 === 1) {
res[mid][mid] = count;
}
return res;
};
螺旋输出*(mxn矩阵,顺时针输出为一维数组)
function spiralPrint(matrix) {
const m = matrix.length;
const n = matrix[0].length;
let startX = startY = 0;
let loop = Math.min(Math.floor(m / 2), Math.floor(n / 2));
while (loop--) {
let row = startX, col = startY;
for (; col < startY + n - 1; col++) {
console.log(matrix[row][col]);
}
for (; row < startX + m - 1; row++) {
console.log(matrix[row][col]);
}
for (; col > startY; col--) {
console.log(matrix[row][col]);
}
for (; row > startX; row--) {
console.log(matrix[row][col]);
}
startX++;
startY++;
m -= 2;
n -= 2;
}
if (m === 1) {
for (let i = startY; i < startY + n; i++) {
console.log(matrix[startX][i]);
}
} else if (n === 1) {
for (let i = startX; i < startX + m; i++) {
console.log(matrix[i][startY]);
}
}
}
const matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
];
spiralPrint(matrix);
旋转矩阵
行<->列,对角线
贪心
Jump Game II
到达last element的最小跳跃次数,nums[i]最远可以跳跃的步数
- 定义两个变量
maxReach
和steps
分别表示当前能到达的最远位置和已经跳跃的步数。 - 遍历数组,对于每个位置
i
,更新maxReach
为当前位置能到达的最远距离。 - 当遍历到
i
超过了maxReach
时,意味着需要再跳一步,并且更新maxReach
为当前位置的最远距离。 - 每次更新
maxReach
时,步数steps
也会增加一次。 - 当遍历完成时,
steps
就是到达数组最后一个元素的最小跳跃次数。
function jump(nums) {
let maxReach = 0; // 当前能到达的最远位置
let steps = 0; // 已经跳跃的步数
let end = 0; // 当前步数内可到达的最远位置
for (let i = 0; i < nums.length - 1; i++) {
maxReach = Math.max(maxReach, i + nums[i]); // 更新最远位置
if (i === end) {
end = maxReach; // 更新当前步数内的最远位置
steps++; // 跳跃一步
}
}
return steps;
}
const nums = [2, 3, 1, 1, 4];
console.log(jump(nums)); // 输出 2
考前复习
应该尽可能多的看各种各样的题目,思考五分钟,想不出来解法的话直接看别人的答案。看懂思路就行了,甚至自己写一遍都没必要,因为比较浪费时间。
笔试的时候最怕的是没思路,所以把各种题型都过目一下,起码心里不会慌,只要有思路,平均一道题二三十分钟搞定还是不难的
mirrors / labuladong / Fucking Algorithm · GitCode