1、扁平数据结构
const menuList = [
{
pid: -1,
name: '购物车',
id: 1,
auth: 'cart',
},
{
pid: 1,
name: '购物车列表',
id: 4,
auth: 'cart-list',
},
{
pid: 4,
name: '彩票',
id: 5,
auth: 'lottery',
},
{
pid: 4,
name: '商品',
id: 6,
auth: 'product',
},
]
// 第一种实现方式 属性
let tree = []
let shuxing = {}
getThree(menuList)
function getThree(param = []) {
param.map((item) => {
shuxing[item.id] = item
shuxing[item.id].children = []
if (item.pid === -1) {
tree = item
}
if (shuxing[item.pid]) {
shuxing[item.pid].children.push(item)
}
})
}
// 第二种实现方式 递归
function getThree2(param = []) {
let root = param.filter((item) => item.pid === -1),
children = param.filter((item) => item.pid !== -1)
setThree22(root, children)
return root
function setThree22(root, children) {
root.forEach((item) => {
children.forEach((sutItem, subIndex) => {
if (item.id === sutItem.pid) {
let childrenArr = JSON.parse(JSON.stringify(children))
childrenArr.splice(subIndex, 1)
setThree22([sutItem], childrenArr)
if (item.children) {
item.children.push(sutItem)
} else {
item.children = [sutItem]
}
}
})
})
}
}
// 第三种filter
function getThree3(param = []) {
const _param = JSON.parse(JSON.stringify(param))
return _param.filter((item) => {
const _arr = _param.filter((subItem) => {
return item.id === subItem.pid
})
_arr && _arr.length > 0 && (item.children = _arr)
return item.pid === -1
})
}
// 自己尝试出来的最简单的方法
const flatteFunction = (arr = [], pid = -1) => {
let result = [];
arr.forEach((element) => {
element.chilren = arr.filter((item) => item.pid === element.id);
if (element.pid === pid) {
result = element;
}
});
return result;
};
2、深度遍历和广度遍历的问题
const data = [ { name: 'a', children: [ { name: 'b', children: [{ name: 'e' }] },
{ name: 'c', children: [{ name: 'f' }] },
{ name: 'd', children: [{ name: 'g' }] },
],
},
{
name: 'a2',
children: [
{ name: 'b2', children: [{ name: 'e2' }] },
{ name: 'c2', children: [{ name: 'f2' }] },
{ name: 'd2', children: [{ name: 'g2' }] },
],
},
]
// 深度遍历, 使用递归
function getName(data) {
const result = []
data.forEach((item) => {
const map = (data) => {
result.push(data.name)
data.children && data.children.forEach((child) => map(child))
}
map(item)
})
return result.join(',')
}
// 广度遍历, 创建一个执行队列, 当队列为空的时候则结束
function getName2(data) {
let result = []
let queue = data
while (queue.length > 0) {
[...queue].forEach((child) => {
queue.shift()
result.push(child.name)
child.children && queue.push(...child.children)
})
}
return result.join(',')
}
console.log(getName(data))
console.log(getName2(data))
3、冒泡排序
const aa = [8,94,15,88,55,76,21,39]
function getSort(param = []) {
let num = null
for (let i = 0; i < param.length - 1; i++) {
for (let j = 0; j < param.length - 1 - i; j++) {
if (param[j] > param[j + 1]) {
num = param[j]
param[j] = param[j + 1]
param[j + 1] = num
}
}
}
return param
}
console.log(getSort(aa))
- 原理 两个循环
- 当 i=0 的时候,里面的循环完整执行,从 j=0 执行到 j=6,这也就是第一遍排序,结果是将最大的数排到了最后,这一遍循环结束后的结果应该是[8,15,88,55,76,21,39,94]
- 当 i=1 的时候,里面的循环再次完整执行,由于最大的数已经在最后了,没有必要去比较数组的最后两项,这也是 j<arr.length-1-i 的巧妙之处,结果是[8,15,55,76,21,39,88,94]
- 说到这里,规律就清楚了,每次将剩下数组里面最大的一个数排到最后面,当第一个循环执行到最后的时候,也就是 i=6,此时,j=0,只需要比较数组的第一和第二项,比较完毕,返回。
4、快排
const aa = [1, 2, 44, 11, 232, 23]
const quickSort = function (arr) {
if (arr.length <= 1) {
return arr //结束
}
const pivotIndex = Math.floor(arr.length / 2)
const pivot = arr.splice(pivotIndex, 1)[0] // 取出这个数据
let left = []
let right = []
for (var i = 0; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return quickSort(left).concat([pivot], quickSort(right))// 递归
}
console.log(quickSort(aa))
5、最长子序列问题(合唱队)
// 牛客 https://www.nowcoder.com/practice/6d9d69e3898f45169a441632b325c7b4?tpId=37&&tqId=21247&rp=1&ru=/ta/huawei&qru=/ta/huawei/question-ranking
function getMaxLength(arr=[1,2,5,4,9,1]){
// result[i]代表第i个位置上升子序列中 元素的 长度
const result = new Array(arr.length).fill(1);
let res = 0;
for(let i = 0; i <arr.length; i++){
for(let j = 0; j < i;j++){
// 和前面的 每一个元素比较,看是否可以,如果可以 当前位置 可以的元素长度 加1
if(arr[j] < arr[i]){
result[i] = Math.max(result[i], result[j]+1)
}
}
res = Math.max(res, result[i])
}
return res
}
console.log('getMaxLength:',getMaxLength())
6、二分查找
// 二分查找
function searching(arr = [], target) {
let start = 0,
end = arr.length - 1,
middle,
element;
while (start <= end) {
middle = Math.floor((start + end) / 2);
console.log('-start + end-', start, end, middle);
element = arr[middle];
console.log('--', target, element, middle);
if (element === target) {
return middle;
} else if (target < element) {
end = middle - 1;
} else {
start = middle + 1;
}
}
return -1;
}
console.log('searching: ', searching([1, 3, 5, 7, 8, 9], 9));
7、手写-实现一个对象的 flatten 方法(阿里)
const obj = {
a: {
b: 1,
c: 2,
d: { e: 5 }
},
b: [1, 3, { a: 2, b: 3 }, [1, 2]],
c: 3
};
// 整体用的递归,通过对对象和数组的不同处理
let flattenObj = {};
function flatten(obj = {}, pre) {
if (typeof obj === 'object' && !Array.isArray(obj)) {// 是对象,而不是数组
for (let key in obj) {
if (typeof obj[key] !== 'object') {
flattenObj[`${pre ? pre + '.' : ''}${key || ''}`] = obj[key];
} else {
const pre1 = pre ? `${pre}.${key}` : key;
flatten(obj[key || ''], pre1);
}
}
} else if (Array.isArray(obj)) { // 数组的处理
console.log('flatten ', obj, pre);
obj.forEach((item, index) => {
const pre1 = `${pre}[${index}]`;
if (typeof item === 'object') {
flatten(item, pre1);
} else {
flattenObj[`${pre1}`] = item;
}
});
}
return flattenObj;
}
// 结果
console.log(flatten(obj));
// {
// 'a.b': 1,
// 'a.c': 2,
// 'a.d.e': 5,
// 'b[0]': 1,
// 'b[1]': 3,
// 'b[2].a': 2,
// 'b[2].b': 3,
// 'b[3][0]': 1,
// 'b[3][1]': 2,
// c: 3
// }
8、手写-判断括号字符串是否有效(小米))
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足: 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。
示例 1: 输入:s = "()" 输出:true
示例 2: 输入:s = "()[]{}" 输出:true
示例 3: 输入:s = "(]" 输出:false
从内部比较的这种思路,值得学习
function isValid1(markWord) {
const markArr = markWord.split('');
if (markArr.length % 2 === 1) {
return false;
}
const obj = { '{': '}', '[': ']', '(': ')' };
let stack=[];
for (let i = 0; i <markArr.length; i++) {
const item = markArr[i];
if(['{',"[","("].includes(item) ){
stack.push(item);
}else{
const pop1 = stack.pop();
if(item!==obj[pop1]){
return false;
}
}
}
if(stack.length){
return false;
}
return true;
}
const s = '[{]()}';
console.log(isValid1(s))
9、手写-查找数组公共前缀(美团)
// 我自己的做法,用了三个for循环
function getMaxLength(markWord = []) {
let maxWords = [];
markWord.forEach(item => {
const itemArr = item.split('');
maxWords.push(itemArr);
});
let commonWord = [];
maxWords[0].forEach((item, index) => {
if (isWord(maxWords, index, item)) {
commonWord.push(item);
}
});
return commonWord;
}
function isWord(maxWords = [], index, item) {
for (let i = 0; i < maxWords.length; i++) {
if (item !== maxWords[i][index]) {
return false;
}
}
return true;
}
const strs = ["cdog","cdracecar","cdar"]
console.log(getMaxLength(strs)); // c d
function getMaxLength(markWord = []) {
let str = markWord[0];
let index = 0,
words,
isGo = true;
while (index < str.length && isGo) {
words = str.slice(0, index);
isGo = isComment(markWord, words);
if (!isGo) {
words = words.slice(0, index - 1);
}
index = index + 1;
}
return words;
}
function isComment(markWord = [], words) {
for (let i = 0; i < markWord.length; i++) {
if (!markWord[i].startsWith(words)) {
return false;
}
}
return true;
}
const strs = ['1cdog', '2cdoracecar', '3cdoar'];
console.log(getMaxLength(strs));
10、手写-字符串最长的不重复子串 (自己没有做出来,网上参考的)
const lengthOfLongestSubstring = function (s) {
if (s.length === 0) {
return 0;
}
let left = 0;
let right = 1;
let maxString = '';
while (right <= s.length) {
let lr = s.slice(left, right);
const index = lr.indexOf(s[right]);
if (index > -1) {
left = index + left + 1;
} else {
lr = s.slice(left, right + 1);
if (lr.length > maxString.length) {
maxString = lr;
}
}
right++;
}
return [maxString.length, maxString];
};
const strs = 'aabcbbc';
console.log(lengthOfLongestSubstring(strs));
11、输入一个正整数,按照从小到大的顺序输出它的所有质因子(重复的也要列举)(如 180 的质因子为 2 2 3 3 5 )最后一个数后面也要有空格
let num = await readline();
num = parseInt(num)
let result = "";
for (let i = 2; i * i <= num; i++) {
while (num % i === 0) {
result = result + i + " ";
num = num / i;
}
}
if (num > 1) result = result + num + " ";
console.log(result);