手撕常见JS面试题

news/2024/12/2 22:37:14/

高阶函数实现AOP(面向切面编程)

    Function.prototype.before = function (beforefn) {let _self = this; // 缓存原函数的引用returnfunction () { // 代理函数beforefn.apply(this, arguments); // 执行前置函数return _self.apply(this, arguments); // 执行原函数}}Function.prototype.after = function (afterfn) {let _self = this;returnfunction () {letset = _self.apply(this, arguments);afterfn.apply(this, arguments);returnset;}}let func = () => console.log('func');func = func.before(() => {console.log('===before===');}).after(() => {console.log('===after===');});func();

输出结果:

===before===
func
===after===   

当我们 new 一个类的时候 都发生了什么

/** * new2 new关键字的代码实现演示 * @param {function} func 被new的类 (构造函数) */
function new2(func) {// 创建了一个实例对象 o,并且这个对象__proto__指向func这个类的原型对象 let o = Object.create(func.prototype); // (在构造函数中this指向当前实例)让这个类作为普通函数值行 并且里面this为实例对象 let k = func.call(o);// 最后再将实例对象返回 如果你在类中显示指定返回值k,// 注意如果返回的是引用类型则将默认返回的实例对象o替代掉return typeof k === 'object' ? k : o;
}// 实验
functionM() { // 即将被new的类this.name = 'liwenli';
}let m = new2(M); // 等价于 new M 这里只是模拟
console.log(m instanceof M); // instanceof 检测实例
console.log(m instanceof Object);
console.log(m.__proto__.constructor === M);

Object.create 兼容实现

let obj1 = {id: 1};Object._create = (o) => {let Fn = function() {}; // 临时的构造函数Fn.prototype = o;return new Fn;}let obj2 = Object._create(obj1);console.log(obj2.__proto__ === obj1); // trueconsole.log(obj2.id); // 1// 原生的Object.createlet obj3 = Object.create(obj1);console.log(obj3.__proto__ === obj1); // trueconsole.log(obj3.id); // 1

currying 函数柯理化

curry 柯理化的实现(递归调用 + valueOf)

知识点:valueOf 浏览器环境下 当我们以log(fn)这种形式取值时,会隐式调用fn自身的valueOf 所以得到的是valueOf的返回值

functionfn() {};
fn.valueOf = () => console.log('valueof');
console.log(fn); // valueofconst mul = x => {const result = y => mul(x * y); // 递归调用mulresult.valueOf = () => x;return result;
}
console.log(mul(2)(3)); // 6// 在上面mul每执行一次,就会返回一个valueOf被改写后的新函数result 并且result执行会在里面调用mul(x * y)
// 在result函数的valueOf里保存着 由上一次x * y 传进来的结果x, 也就是上一次x*y 会作为这一次的输出 依然叫x// 第一次mul(2) 此时 x为2  return result
result 为 result = y => mul(2 * y); 
// 第二次 mul(2)(3) 等价于 第一个mul返回的result(3), result执行 => mul(2 * 3) 再次调用mul 将2*3 = 6 的结果作为mul参数
// 最后mul(6) x = 6 在返回一个新函数result 此时result的valueOf = () => 6// log(mul(2)(3)) 相当于log的最后返回的result 隐式调用valueOf 返回 6

curry 将多参数函数转换为接收单一参数的函数

function fe(a, b, c) {return a + b + c;
}function curry(fe) {let args = []; // 参数集合let len = args.length;returnfunctionbar() {args = [...args, ...arguments]; // 收集参数if (args.length >= fe.length) {return fe.apply(this, args);}return bar;}
}console.log(curry(fe)(1)(2)(3)); // 6

参考 前端进阶面试题详细解答

currying 部分求值

    // currying 函数柯理化let currying = function(fn) {let args = [];returnfunctionfe() {if (arguments.length === 0) {return fn.apply(this, args);}[].push.apply(args, arguments);return fe;}}let count = currying(function (...rest) {return rest.reduce((prev, cur) => prev + cur, 0);});console.log(count(100)(200)(10)()); // 310

收集参数 延迟执行 到达指定次数才执行

   // 参数收集 指定次数后执行function fn(...rest) {console.log(rest);};function after(fn, time = 1) {let params = [];returnfunction(...rest) {params = [...params, ...rest];if (--time === 0) {fn.apply(this, params);}}}let newFn = after(fn, 3); // 执行3次 内部fn才会执行newFn(2);newFn(3);newFn(4);

函数节流

throttle 策略的电梯。保证如果电梯第一个人进来后,50毫秒后准时运送一次,不等待。如果没有人,则待机。

let throttle = (fn, delay = 50) => { // 节流 控制执行间隔时间 防止频繁触发 scroll resize mousemovelet stattime = 0;returnfunction (...args) {let curTime = new Date();if (curTime - stattime >= delay) {fn.apply(this, args);stattime = curTime;}}}

防抖动

debounce 策略的电梯。如果电梯里有人进来,等待50毫秒。如果又人进来,50毫秒等待重新计时,直到50毫秒超时,开始运送。

let debounce = (fn, time = 50) => { // 防抖动 控制空闲时间 用户输入频繁let timer;returnfunction (...args) {let that = this;clearTimeout(timer);timer = setTimeout(fn.bind(that, ...args), time);}}

深度拷贝兼容写法(不包括原型属性)

function deepCopy(obj) {if (typeof obj !== 'object') return obj;if (typeof window !== 'undefined' && window.JSON) { // 浏览器环境下 并支持window.JSON 则使用 JSONreturn JSON.parse(JSON.stringify(obj));} else {let newObj = obj.constructor === Array ? [] : {};for(let key in obj) {newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];}return newObj;}
}let obj = {a: 1, b: [12]};
let newObj = deepCopy(obj);
newObj.b[1] = 100;
console.log(obj);
console.log(newObj);

Function的bind实现

Function.prototype._bind = function(context) {let func = this;let params = [].slice.call(arguments, 1);returnfunction() {params = params.concat([].slice.call(arguments, 0));func.apply(context, params);}
}let obj = {id: 24}function fn1(a) {console.log(this, arguments);
}
let foo = fn1._bind(obj, obj.id);

函数组合串联compose(koa reduce中间件)

// 组合串联
let fn1 = (a) => a + 1;
let fn2 = (b) => b + 2;
let fn3 = (c) => c + 3;let funs = [fn1, fn2, fn3];let compose = (func) => {return arg => func.reduceRight((composed, fn) => fn(composed), arg);
}
console.log(compose(funs)(100)); // 相当于fn1(fn2(fn3(100)))

co函数

function* fn(a) {a = yield a;let b = yield 2;let c = yield 3;return a + b + c;
}function co(fn, ...args) {let g = fn(...args);return new Promise((resolve, reject) => {function next(lastValue) {let { value, done } = g.next(lastValue);if (done) {resolve(value);} else {if (value instanceof Promise) {value.then(next, (val) => reject(val));} else {next(value)}}}next();});
}
co(fn, 100).then(value => {console.log(value); // 105
});

如何主动中止Promise调用链

const p1 = new Promise((resolve, reject) => {setTimeout(() => { // 异步操作resolve('start')}, 1000);
});p1.then((result) => {console.log('a', result); return Promise.reject('中断后续调用'); // 此时rejected的状态将直接跳到catch里,剩下的调用不会再继续
}).then(result => {console.log('b', result);
}).then(result => {console.log('c', result);
}).catch(err => {console.log(err);
});// a start
// 中断后续调用

bluebird.promisify实现(将异步回调函数api 转换为promise形式)

// promisify.js
module.exports = {promisify(fn){returnfunction () {var args = Array.from(arguments);return new Promise(function (resolve, reject) {fn.apply(null, args.concat(function (err) {if (err) {reject(err);} else {resolve(arguments[1])}}));})}}
}// main.js
const fs = require('fs');
const {promisify} = require('./promisify.js');const readFile = promisify('fs.readFile'); // 转换异步读取// 异步文件 由回调函数形式变成promise形式
readFile('./1.txt', 'utf8').then(data => { console.log(data);
}).catch(err => {console.log(err);
});

window.requestAnimationFrame兼容性处理

window._requestAnimationFrame = (function(){return  window.requestAnimationFrame       ||window.webkitRequestAnimationFrame ||window.mozRequestAnimationFrame    ||function(callback){window.setTimeout(callback, 1000 / 60);};
})();

字符串是否符合回文规则

let str = 'My age is 0, 0 si ega ym.';方法一
function palindrome(params) {params = params.replace(/[\W\s_]/ig, '');return params.toLowerCase()  === params.split('').reverse().join('').toLowerCase();
}
console.log(palindrome(str));方法二
function palindrome(params) {params = params.replace(/[\W\s_]/ig, '').toLowerCase();for (var i = 0, j = params.length-1; i<j; i++, j--) {if (params[i] !== params[j]) {returnfalse;}}returntrue;
}

解构

// 将 destructuringArray([1, [2, 3], 4], "[a, [b], c]") => {a: 1, b: 2, c: 4}
const targetArray = [1, [2, 3], 4];
const formater = "[a, [b], c]";const destructuringArray = (values, keys) => {try {const obj = {};if (typeof keys === 'string') {keys = JSON.parse(keys.replace(/\w+/g, '"$&"'));}const iterate = (values, keys) =>keys.forEach((key, i) => {if(Array.isArray(key)) iterate(values[i], key)else obj[key] = values[i]})iterate(values, keys)return obj;} catch (e) {console.error(e.message);}
}

数组展平

将[[1, 2], 3, [[[4], 5]]] 展平为 [1, 2, 3, 4, 5]

let arr = [[1, 2], 3, [[[4], 5]]]; // 数组展平
function flatten(arr) {return [].concat(...arr.map(x => Array.isArray(x) ? flatten(x) : x))
}

二分查找

const arr = [1, 2, 3, 4, 5, 6, 7, 8];
// 二分查找 递归 由中间开始往两边查找 前提是有序的数组 返回对应的索引位置
function binarySearch1(arr, dest, start = 0, end = data.length) {if (start > end) {return -1}let midIndex = Math.floor((start + end) / 2); // 中间位置索引let mid = arr[midIndex]; // 中间值if (mid == dest) {return midIndex;}if (dest < mid) { // 要找的比中间值小 就从中间往开头找 一直到0return binarySearch1(arr, dest, 0, midIndex - 1);}if (dest > mid) { // 要找的比中间值大 就从中间往后找 一直到end结束return binarySearch1(arr, dest, midIndex + 1, end);}return -1; // 找不到返回-1
}
console.log(binarySearch1(arr, 7, 3, 6)); // 6// 非递归 arr前提有序数组 (从小到大)返回对应的索引位置 
function binarySearch2(arr, dest) {let max = arr.length - 1;let min = 0;while (min <= max) {let mid = Math.floor((max + min) / 2); // mid中间位置索引if (dest < arr[mid]) { // 如果要找的这项比中间项还要小 说明应该在mid中间位置前面 修改最大边界值max=mid-1 max = mid - 1;} elseif (dest > arr[mid]) { // 如果要找的这项比中间项还要大 说明应该在mid中间位置的后面 修改最小边界值min=mid+1min = mid + 1;} else {return mid;}}return -1; // 找不到返回-1
}
console.log(binarySearch2(arr, 3)); // 2

找出数组中重复出现过的元素

// 例如:[1,2,4,4,3,3,1,5,3]
// 输出:[1,3,4]
let arr = [1, 2, 4, 4, 3, 3, 1, 5, 3];// 方法一
function repeat1(arr){var result = [], map = {};arr.map(function(num){if(map[num] === 1) result.push(num); // 等于1说明之前出现过一次 这次重复出现了map[num] = (map[num] || 0) + 1; // 微妙之处 开始第一次出现无值 记为 0 + 1 = 1 下一次从1开始累加});return result;
}
console.log(repeat1(arr));// 方法二function repeat(arr) {let result = arr.filter((x, i, self) => {return self.indexOf(x) === i && self.lastIndexOf(x) !== i}); // return result;
}
console.log(repeat(arr));

数组中按照数字重复出现的次数进行排序

// 如果次数相同 则按照值排序 比如  2, 2, 2和 1, 1, 1  应排序为 [1, 1, 1, 2, 2, 2]
// 比如 [1,2,1,2,1,3,4,5,4,5,5,2,2] => [3, 4, 4, 1, 1, 1, 5, 5, 5, 2, 2, 2, 2]let arr = [9, 7, 7, 1, 2, 1, 2, 1, 3, 4, 5, 4, 5, 5, 2, 2];
function sortArray(arr) {let obj = {};let newArr = [];for(let i = 0; i < arr.length; i++) {let cur = arr[i];if(obj[cur]){obj[cur].push(cur);continue;}obj[cur] = [cur];}for(let k in obj) {if(obj.hasOwnProperty(k)) {newArr.push(obj[k])}}newArr.sort((a, b) => {if(a.length === b.length){return a[0] - b[0];}return a.length - b.length;});newArr = newArr.reduce((prev, cur) => prev.concat(cur));return newArr;}console.log(sortArray(arr)); // [ 3, 9, 4, 4, 7, 7, 1, 1, 1, 5, 5, 5, 2, 2, 2, 2 ]

不用循环,创建一个长度为 100 的数组,并且每个元素的值等于它的下标。

// 方法一 递归写法
function createArray(len, arr = []) {if (len > 0) {arr[--len] = len;createArray(len, arr);}return arr;
}
console.log(createArray(100)); // 方法二// 下面评论中@MaDivH 提供的实现方法 长度为 100 的数组 
Array(100).fill().map((_,i)=>i+1);// 方法三
[...Array(100).keys()]

根据关键词找出 所在对象id

var docs = [{id: 1,words: ['hello', "world"]}, {id: 2,words: ['hello', "hihi"]}, {id: 3,words: ['haha', "hello"]}, {id: 4,words: ['world', "nihao"]}
];
findDocList(docs, ['hello']) // 文档id1,文档id2,文档id3
findDocList(docs, ['hello', 'world']) // 文档id1
function findDocList(docs, word = []) {if (word.constructor !== Array) return;let ids = [];for (let i = 0; i < docs.length; i++) {let {id, words} = docs[i];let flag = word.every((item) => {return words.indexOf(item) > -1;});flag && ids.push(id);}return ids;
}
findDocList(docs, ['hello', 'world']);

getElementsByClassName 兼容写法

function getByClass(cName) {if ('getElementsByClassName'in this) {return this.getElementsByClassName(cName);}cName = cName.replace(/(^\s+|\s+$)/g, '').split(/\s+/g);let eles = this.getElementsByTagName('*');for (let i = 0; i < cName.length; i++) {let reg = new RegExp(`(^| )${cName[i]}( |$)`);let temp = [];for (let j = 0; j < eles.length; j++) {let cur = eles[j];let {className} = cur;if (reg.test(className)) {temp.push(cur);}}eles = temp;}return eles;}console.log(content.getByClass('c1 c2 '));

插入排序

插入排序 从后往前比较 直到碰到比当前项 还要小的前一项时 将这一项插入到前一项的后面

function insertSort(arr) {let len = arr.length;let preIndex, current;for (let i = 1; i < len; i++) {preIndex = i - 1;current = arr[i]; // 当前项while (preIndex >= 0 && arr[preIndex] > current) {arr[preIndex + 1] = arr[preIndex]; // 如果前一项大于当前项 则把前一项往后挪一位preIndex-- // 用当前项继续和前面值进行比较}arr[preIndex + 1] = current; // 如果前一项小于当前项则 循环结束 则将当前项放到 前一项的后面}return arr;
}

选择排序

选择排序 每次拿当前项与后面其他项进行比较 得到最小值的索引位置 然后把最小值和当前项交换位置

function selectSort(arr) {let len = arr.length;let temp = null;let minIndex = null;for (let i = 0; i < len - 1; i++) { // 把当前值的索引作为最小值的索引一次去比较minIndex = i; // 假设当前项索引 为最小值索引for (let j = i + 1; j < len; j++) { // 当前项后面向一次比小if (arr[j] < arr[minIndex]) { // 比假设的值还要小 则保留最小值索引minIndex = j; // 找到最小值的索引位置}}// 将当前值和比较出的最小值交换位置if (i !== minIndex) {temp = arr[i]arr[i] = arr[minIndex];arr[minIndex] = temp;}}return arr;
}

冒泡排序

冒泡排序 相邻两项进行比较 如果当前值大于后一项 则交换位置

function bubleSort(arr) {let length = arr.length;let temp = null;for (let i = 0; i < length - 1; i++) { // 控制轮数let flag = false; // 当前这轮是否交换过标识for (let l = 0; l < length - i - 1; l++) { // 控制每轮比较次数if (arr[l] > arr[l + 1]) {temp = arr[l];arr[l] = arr[l + 1];arr[l + 1] = temp;flag = true; // 如果发生过交换flag则为true} }if (!flag) { // 优化  如果从头到尾比较一轮后 flag依然为false说明 已经排好序了 没必要在继续下去temp = null;return arr;}}
}

快速排序(递归)

function quickSort(arr) {if (arr.length <= 1) return arr;let midIndex = Math.floor(arr.length / 2);let midNum = arr.splice(midIndex, 1)[0];let left = [];let right = [];for(let i = 0; i < arr.length; i++) {let cur = arr[i];if (cur <= midNum) {left.push(cur);} else {right.push(cur);}}return quickSort(left).concat(midNum, quickSort(right));
}let arr = [2, 4, 12, 9, 22, 10, 18, 6];
quickSort(arr);

数组去重几种方法

const arr = [1, 2, 1, 2, 3, 4, 2, 1, 3];// 1 ES6
let newArr = [...new Set(arr)];// 2
const arr = [1, 2, 1, 2, 3, 4, 'l', 2, 1, 3, 'l'];
const newArr = arr.filter(function(ele, index, array) {return index === array.indexOf(ele)
});
console.log(newArr); // [ 1, 2, 3, 4, 'l' ]// 3
Array.prototype.unique2 = function() {let newArr = [];let len = this.length;for(let i = 0; i < len; i++) {let cur = this[i];if(newArr.indexOf(cur) === -1) {newArr[newArr.length] = cur;}}return newArr;
}
console.log(arr.unique1());// 4
Array.prototype.unique3 = function() {let newArr = this.slice(0);let len = this.length;let obj = {};for(let i = 0; i < len; i++) {let cur = newArr[i];if(obj[cur]) {newArr[i] = newArr[newArr.length - 1];newArr.length--;i--;continue;}obj[cur] = cur;}return newArr;
}
console.log(arr.unique3());// 5
Array.prototype.unique4 = function() {let json = {}, newArr = [], len = this.length;for(var i = 0; i < len; i++) {let cur = this[i];if (typeof json[cur] == "undefined") {json[cur] = true;newArr.push(cur)}}return newArr;
}
console.log(arr.unique4());

千分符

方法一

// 处理数字
let str1 = 2123456789;
let str2 = 2123456789.12;
console.log(str1.toLocaleString()); // 2,123,456,789
console.log(str2.toLocaleString()); // 2,123,456,789.12

方法二

    // 处理字符串let str1 = '2123456789';let str2 = '2123456789.12';// 利用正向预查 匹配 开头一个数字\d 后面匹配这个数字后面必须是三个数字为一组为结尾或小数为结尾function thousandth(str) { let reg = /\d(?=(?:\d{3})+(?:\.\d+|$))/g; return str.replace(reg, '$&,');}console.log(thousandth(str1)); // 2,123,456,789console.log(thousandth(str2)); // 2,123,456,789.12

在一个数组中 如a、b两项, 要保证a和b两项的差 与 a和b两项索引的差 的相加后的结果max 是数组中其他两项max 中的最大值 找出符合条件两项a, b的值 (不可以排序 或改变数组位置) 如:

let max = (a - b) + (a的索引- b的索引);
求a b

答案:

// 思路:其实也就是找出数组中当前的每一项与自身索引相加后的和的最大值以及与索引相加后的最小值的和 找出符合条件的两项即可 如 let result = (maxItem-minItem) + (maxIndex-minIndex) 等价于 (maxItem+maxIndex) - (minItem+minIndex)// let arr = [1, 2, 3, 4, 5, 6]; // 最简单的测试数组 最小项1 最大项6
// 很显然这个数组中最大值6与索引相加(6+5)是当中最大值11 1与索引相加(1+0)为当中的最小值1(6 + 5)-(1+0)= 10// 假设法
let arr = [2, 10, 9, 1, 8, 3, 4];
let minItem = arr[0]; // 假设第一项与自身索引的和是最小值 索引为0因此省略
let maxItem = arr[0]; // 假设第一项与自身索引的和是最大值 索引为0因此省略
let min = minItem; // 最小项
let max = maxItem; // 最大项
let minIndex = 0; // 最小项索引
let maxIndex = 0; // 最大项索引
for(let i = 1; i < arr.length; i++) {let cur = arr[i] + i; // 当前项和自身索引的和cur < minItem ? (minItem = cur, min = arr[i], minIndex = i) : null;cur > maxItem ? (maxItem = cur, max = arr[i], maxIndex = i) : null;
}
console.log(maxItem, minItem); // 最大项与索引的和 最小项与索引的和
console.log(max, min); // 最大项 最小项
console.log(maxIndex, minIndex); // 最大项的索引 最小项的索引

检测 字符串中括号表达式是否平衡

//balance('[()') = false; balance('[()()()]') = true
//function match(a, b) {return (a === '(' && b === ')') || (a === ')' && b === '(') || (a === '[' && b === ']') || (a === ']' && b === '[');
}function balance(str) {if (str.length % 2 === 0) {let len = str.length;for (let i = 0, j = len - 1; i < len / 2; i++, j--) {if (!match(str[i], str[j])) {returnfalse;}}returntrue;}returnfalse;
}
console.log(balance('[()()()]')); // true
console.log(balance('[()')); // false
console.log(balance('[]()')); // false
//function is_balance(str) {return [...str].reduce((stack, c) => {match(stack[stack.length - 1], c) ?stack.pop() : stack.push(c);return stack;}, []).length === 0;
}
console.log(is_balance('[()()()]')); // true
console.log(is_balance('[()')); // false
console.log(is_balance('[]()')); // false

求相邻两项最大和

// 一
let arr1 = [-1, 3, 1, -5, 2]; // 如 [2, 4, -4, -3] => 4
function sum(arr) {let prev = arr[0];let sumArr = [];let len = arr.length;for(let i = 1; i < len; i++) {let cur = arr[i];sumArr.push(cur + prev);prev = cur;}   return Math.max(...sumArr);
}
console.log(sum(arr1));// 二
function maxsum(arr) {const M = [arr[0]];let max = M[0];for(let i = 1; i < arr.length; i++) {M[i] = Math.max(arr[i], M[i - 1] + arr[i]);max = Math.max(M[i], max);}return max;
}

字符串去除相邻的重复项 如:‘aabbccddeexxxxaa’ => ‘abcdexa’

// 正则表达式
let str = 'aabbccddeexxxxaa';
function uniq1(str) {// return str.replace(/([a-z])(\1){1,}/g, '$1');return str.replace(/(.)(?=\1)/g, '');
}
console.log(uniq1(str));// 数组方式
function uniq2(str) {let arr = str.split('');let newArr = [arr[0]];for(let i = 1; i < arr.length; i++) {let cur = arr[i];if (cur !== newArr[newArr.length - 1]) {newArr.push(cur);}}return newArr.join('');
}
console.log(uniq2(str));

http://www.ppmy.cn/news/26200.html

相关文章

Python获取zabbix问题触发器

背景&#xff1a;阿里云的ECS服务器因为阿里云升级插件&#xff0c;导致安全防护程序重启&#xff0c;产生不同的端口。导致低自动发现注册的端口 大量报警。 解决&#xff1a;杀掉关于因为非业务 变更的端口检测的触发器。 相关文档&#xff1a; Zabbix监控之主机端口监控自…

java8转换数组。找到最接近指定数据

List<String> lsstrArrays.asList(arear);//数组转listList<String> listWithoutNulls lsstr.stream().filter(Objects::nonNull)//list去掉空值.collect(Collectors.toList());String[] toBeStored new String[listWithoutNulls.size()];//list转数组listWithou…

学习 Python 之 Pygame 开发坦克大战(三)

学习 Python 之 Pygame 开发坦克大战&#xff08;三&#xff09;坦克大战物体碰撞检测编写1. 实现敌方坦克与我方坦克间的碰撞2. 实现敌方坦克间的碰撞3. 实现玩家子弹与敌方坦克间的碰撞4. 实现敌方子弹与我方坦克间的碰撞 和 玩家复活5. 爆炸效果类6. 为子弹爆炸添加爆炸效果…

【数据结构】——队列

文章目录前言一.什么是队列&#xff0c;队列的特点二、队列相关操作队列的相关操作声明队列的创建1.队列的初始化2.对队列进行销毁3.判断队列是否为空队列4.入队操作5.出队操作6.取出队头数据7. 取出队尾数据8.计算队伍的人数总结前言 本文章讲述的是数据结构的特殊线性表——…

管理会计报告和财务报告的区别

财务会计报告是给投资人看的&#xff0c;可以反映公司总体的盈利能力。不过&#xff0c;我们回顾一下前面“第一天”里面提到的问题。如果你是公司的产品经理&#xff0c;目前有三个产品在你的管辖范围内。上级给你一笔新的资金&#xff0c;这笔资金应该投到哪个产品上&#xf…

华为OD机试 - 叠放书籍(Python) | 机试题算法思路 【2023】

最近更新的博客 华为OD机试 - 寻找路径 | 备考思路,刷题要点,答疑 【新解法】 华为OD机试 - 五键键盘 | 备考思路,刷题要点,答疑 【新解法】 华为OD机试 - IPv4 地址转换成整数 | 备考思路,刷题要点,答疑 【新解法】 华为OD机试 - 对称美学 | 备考思路,刷题要点,答疑 …

centos7安装RabbitMQ

1、查看本机基本信息 查看Linux发行版本 uname -a # Linux VM-0-8-centos 3.10.0-1160.11.1.el7.x86_64 #1 SMP Fri Dec 18 16:34:56 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux cat /etc/redhat-release # CentOS Linux release 7.9.2009 (Core)2、创建创建工作目录 mkdir /…

就业大山之下的网络安全:安逸的安服仔

从去年开始&#xff0c;各个互联网大厂就接二连三的放出了裁员消息&#xff0c;整个互联网行业好像都处于寒冬状态。微博、小米、滴滴、知乎、拼多多等在内的一大批互联网知名企业&#xff0c;也相继传出“人员优化”的消息。 除了国内市场的萧条&#xff0c;国外市场也是不容…