【小番茄夫斯基】全网最全前端面试手撕算法题,原理手写汇总

2023-05-16

文章目录

  • 深拷贝
  • 柯里化函数
  • 实现 instanceof
  • 手写 new
  • 数组去重
  • flat 拍平数组
  • ObjectDefineProperty实现双向数据绑定
  • setInterval 实现 setTimeout
  • setTimeout 实现 setInterval
  • this 绑定 apply,call,bind
  • apply
  • call
  • bind
  • 手写 promise
  • promissAll
  • promiseFinally
  • promiseRace
  • promiseReject
  • prmiseResole
  • 防抖,节流
  • 排序算法
  • 快速排序
  • 选择排序
  • 插入排序
  • 归并排序
  • 冒泡排序
  • 希尔排序
  • 继承
  • 原型链继承
  • 构造函数继承
  • 组合继承(原型链继承 + 构造函数继承)
  • 原型式继承
  • 寄生式继承
  • 组合寄生式继承
  • ES6 继承
  • 算法题
  • 大数相加
  • 哈夫曼树
  • 千分位分隔符
  • 最大公约数

深拷贝

// 简单版本
// function deepClone1(obj) {
//   return JSON.parse(JSON.stringify(obj));
// }



function deepClone(obj = {}) {
  if (typeof obj !== "object" && obj !== null) return obj;
  let result = obj instanceof Array ? [] : {};

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      result[key] = deepClone(obj[key]);
    }
  }
  return result;
}

let obj = {
  name: "kunyuan",
  age: 15,
  da: {
    name: "45",
  },
};

let newObj = deepClone(obj);
newObj.name = "laj";
newObj.da.name = "aaaaaaaa";
console.log(obj);
console.log(newObj);
<img src="" alt="" width="30%" />

柯里化函数

// 第一种:固定传入参数,参数够了才执行

/** * 实现要点:柯里化函数接收到足够参数后,就会执行原函数,那么我们如何去确定何时达到足够的参数 呢?
 * * 柯里化函数需要记住你已经给过他的参数,如果没给的话,则默认为一个空数组。
 * * 接下来每次调用的时候,需要检查参数是否给够,如果够了,则执行fn,
 * 没有的话则返回一个新的 curry 函数,将现有的参数塞给他。 **/

// 待柯里化处理的函数
let sum = (a, b, c, d) => {
  return a + b + c + d;
};

// 柯里化函数,返回一个被处理过的函数

let curry = (fn,...args) => { 
  // arr 记录已有参数
  return args.length >= fn.length ? fn(...args) : (...arr)=> curry(fn,...args.concat(...arr))
}

var sumPlus = curry(sum);

console.log(sumPlus(1)(2)(3)(4));
console.log(sumPlus(1, 2)(3)(4));
console.log(sumPlus(1, 2, 3)(4));


实现 instanceof

function myInstanceOf(left, right) {
  let leftValue = left.__proto__;
  let rightValue = right.prototype;

  while (true) {
    if (leftValue == null) return false;
    if (leftValue === rightValue) {
      return true;
    }
    leftValue = leftValue.__proto__;
  }
}

function getType(type) {
  return Object.prototype.toString.call(type).slice(8, -1);
}

console.log(myInstanceOf(Object, Function));
console.log(getType(1));

手写 new

function mynew(func, ...args) {

  let obj = {};
  obj.__proto__ = func.prototype;
  let result = func.apply(obj, args);
  return result instanceof Object ? result : obj; 
}



function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.say = function () {
  console.log(this.name + ' ' + this.age);
}

let p = mynew(Person, "邬坤源", 12);
console.log(p);
p.say();

数组去重

var array = [1, 2, 1, 1, '1'];


// Array.from去重
function uniques(array){
  return Array.from(new Set(array));   
}

// 简化
function SampleUniques(array){
  return [...new Set(array)]
}
console.log(uniques(array));

// 也可以使用es5中的indexOf方法
function es5Uniques(array){
  let res  = array.filter(function(item,index,array){
    return array.indexOf(item) === index;
  })
  return res;
}

console.log("es5去重");
console.log(es5Uniques(array));

flat 拍平数组

const arr = [1, [2, 3, [4, [[5]]]]]

console.log(arr.flat(1));
console.log(arr.flat(2));
console.log(arr.flat(3));
console.log(arr.flat(4));

// depth<=0时,返回的数组和原数组维数一样(注意只是维数一样,空位情况见第3点)
console.log("depth<=0时,返回的数组和原数组维数一样(注意只是维数一样,空位情况见第3点)");
console.log(arr.flat(0));

console.log([].concat(...arr));

// 自己实现一个flat扁平化数组
function myflat(arr){
  while(arr.some(item=>Array.isArray(item))){
      arr = [].concat(...arr)
  }
  return arr;
}
console.log("我的实现");
console.log(myflat(arr));

// 重写原型上的方法
Array.prototype.newflat = function(n=1){

  let arr = this;
  while(n && this.some(item=>Array.isArray(item))){
    arr = [].concat(...arr);
    n--;
  }
  return arr;
}
console.log("重写原型上的方法");
console.log([1, 2, [3, 4, [5, [6, [7]]]]].newflat(5))


// 使用reduce方法拍平数组
function FlatReduce(arr){
  return arr.reduce((pre,cur) => {
    return pre.concat(Array.isArray(cur)?FlatReduce(cur):cur)
  },[])
}

ObjectDefineProperty实现双向数据绑定

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
</head>

<body>
  <div id="app">
    <input type="text" value="" name="txt" id="txt">
    <p id="Show_text"></p>
  </div>

  <script>
    var obj = {};
    Object.defineProperty(obj, 'value', {
      get: function () {
        return obj;
      },
      set: function (newValue) {
        document.getElementById('txt').value = newValue
        document.getElementById('Show_text').innerHTML = newValue
      },

    })
    document.addEventListener('keyup', function (e) {
      obj.value = e.target.value
    })
  </script>
</body>

</html>

setInterval 实现 setTimeout

const mySetTimeout = (fn, delay) => {
  const timer = setInterval(() => {
    fn()
    clearInterval(timer)
  }, delay)
}

setTimeout 实现 setInterval

const mySetInterval = (fn, delay) => {
  let timer = null
  const interval = () => {
    fn()
    timer = setTimeout(interval, delay)
  }
  timer = setTimeout(interval, delay)

  return {
    cancel: () => {
      clearTimeout(timer)
    }
  }
}

this 绑定 apply,call,bind

apply

Function.prototype.myApply = function(context=globalThis,...args){

  let key = Symbol('key');
  context[key] = this;
  let result = context[key](args);
  delete context[key];
  return result;
}

function f(a,b){
  console.log(a+b)
  console.log(this.name)
 }

 let obj={
  name:'张三'
 }
 f.myApply(obj,[1,2])

call

Function.prototype.newCall = function(context=globalThis,...args) {

  let key = Symbol('key')
  context[key] = this
  let result = context[key](...args)
  delete context[key]
  return result;  
}
function f(a,b){
  console.log(a+b)
  console.log(this.name)
 }

 let obj={
  name:1
 }
 f.newCall(obj,1,2)

bind

const obj = {
  name: "11",
  fun() {
    console.log(this.name);
  },
};
Function.prototype._bind = function (ctx, ...args) {
  // 获取函数体
  const _self = this;
  // 用一个新函数包裹,避免立即执行
  const bindFn = (...reset) => {
    return _self.call(ctx, ...args, ...reset);
  };
  return bindFn;
};
const obj2 = { name: "22" };
obj.fun(); // 11
const fn = obj.fun.bind(obj2);
const fn2 = obj.fun._bind(obj2);
fn(); // 22
fn2(); // 22

手写 promise

promissAll

function promiseAll(promises){
  if(!Array.isArray(promises)){
    throw new TypeError("promises must be an array")
  }

  return new Promise(function(resolve, reject){
    // 数组长度
    let promiseNum = promises.length;
    // 成功的数量
    let resolveCount  = 0;
    // 成功的值的数组
    let resolveValues = new Array(promiseNum);
    // 先遍历
    for(let i=0; i<promiseNum; i++){
      // 为什么不直接 promise[i].then, 因为promise[i]可能不是一个promise
      Promise.resolve(promises[i]).then(function(value){
        resolveValues[i] = value;
        resolveCount++;
        if(resolveCount == promiseNum){
          return resolve(resolveValues)
        }
      },
      function(err){
        return reject(err);
      }
      )
    }
  })
}

promiseFinally

Promise.prototype.finally = function(callback) {
  this.then(value => {
    return Promise.resolve(callback()).then(() => {
      return value;
    })
  }, error => {
    return Promise.resolve(callback()).then(() => {
      throw error;
    })
  })
}

promiseRace

// function promiceRaces(promises){

//   if(!Array.isArray(promises)){
//     throw new TypeError("promise must be an array")
//   }
//   return new Promise(function(resolve, reject){
//     promises.forEach( p =>
//       Promise.resolve(p).then(data=>{
//         resolve(data)
//       },err =>{
//         reject(err)
//       }
//       )
      
//       )
//   })

// }


function PromiseRace(promises) {

  if(promises instanceof Array){
    throw new TypeError("promises must be an array")
  }

  return new Promise(function(resole,reject){
    promises.forEach( item =>{
        Promise.resolve(item).then(data=>{
          resole(data)
        },
        err =>{
          reject(err)
        }
        )
    })
  })

}

promiseReject

Promise.reject = function(reason){
 
  return new Promise((resolve, reject)=>reject(reason))
}

prmiseResole

Promise.resolve = function(value) {

  if(value instanceof Promise){
    return value;
  }
  return new Promise((resolve, reject)=>resolve(value))

}

防抖,节流

// 防抖
// 防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时


const debounce = (func,wait = 500) => {
  var timer = 0;
  return function(...args) {
    if(timer) clearTimeout(timer);
    timer = setTimeout(()=>{
      func.apply(this,args);
    },wait);
  }
}

const fn = debounce(()=>{console.log(3);},3000)
setInterval(fn, 2000)


// 节流
// 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效


// func是用户传入需要防抖的函数
// wait是等待时间
const throttle = (func, wait = 500) => {
  // 上一次执行该函数的时间
  let lastTime = 0
  return function (...args) {
    // 当前时间
    let now = +new Date()
    // 将当前时间和上一次执行函数时间对比
    // 如果差值大于设置的等待时间就执行函数
    if (now - lastTime > wait) {
      lastTime = now
      func.apply(this, args)
    }
  }
}

const fn = throttle(() => {
  console.log(3);
}, 3000)

setInterval(fn, 2000)

// 适用场景:

// 拖拽场景:固定时间内只执行一次,防止超高频次触发位置变动
// 缩放场景:监控浏览器resize
// 动画场景:避免短时间内多次触发动画引起性能问题

排序算法

快速排序

// 快速排序
function QuickSort(arr) {

    const n = arr.length;
    if (n <= 1) return arr;
    let pivot = arr[0];

    let left = [];
    let right = [];

    for (let i = 1; i < n; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }
    // return QuickSort(left).concat([pivot], QuickSort(right));
    return [...QuickSort(left), pivot, ...QuickSort(right)]
}
let list = [4, 6, 8, 5, 9, 1, 2, 3, 2];

let sortArr = QuickSort(list)
console.log("快速排序", sortArr);

选择排序

function selectionSort(arr) {
    var len = arr.length;
    var minIndex, temp;
    for (var i = 0; i < len - 1; i++) {
        minIndex = i;
        for (var j = i + 1; j < len; j++) {
            if (arr[j] < arr[minIndex]) { // 寻找最小的数
                minIndex = j; // 将最小数的索引保存
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    return arr;
    }

插入排序

function insertionSort(arr) {
    var len = arr.length;
    var preIndex, current;
    for (var 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;
}

归并排序

const mergeSort = arr => {
    //采用自上而下的递归方法
    const len = arr.length;
    if (len < 2) {
        return arr;
    }
    // length >> 1 和 Math.floor(len / 2) 等价
    let middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle); // 拆分为两个子数组
    return merge(mergeSort(left), mergeSort(right));
};

const merge = (left, right) => {
    const result = [];

    while (left.length && right.length) {
        // 注意: 判断的条件是小于或等于,如果只是小于,那么排序将不稳定.    
        if (left[0] <= right[0]) {
            result.push(left.shift());
        } else {
            result.push(right.shift());
        }
    }

    while (left.length) result.push(left.shift());

    while (right.length) result.push(right.shift());

    return result;
};

// 测试
const arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48];
console.time('归并排序耗时');
console.log('arr :', mergeSort(arr));
console.timeEnd('归并排序耗时');
// arr : [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
// 归并排序耗时: 0.739990234375ms

冒泡排序

function bubbleSort(arr) {
    var len = arr.length;
    for (var i = 0; i < len - 1; i++) {
        for (var j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) { // 相邻元素两两对比
                var temp = arr[j + 1]; // 元素交换
                arr[j + 1] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr;
}

希尔排序

function shellSort(arr) {
    // 1. 获取数组长度
    let length = arr.length

    // 2.获取初始的间隔长度
    let interval = Math.floor(length / 2)

    // 3. 不断地缩小间隔的大小,进行分组插入排序
    while (interval >= 1) {

        // 4. 从 arr[interval] 开始往后遍历,将遍历到的数据与其小组进行插入排序
        for (let i = interval; i < length; i++) {
            let temp = arr[i]
            let j = i
            while (arr[j - interval] > temp && j - interval >= 0) {
                arr[j] = arr[j - interval]
                j -= interval
            }

            arr[j] = temp
        }

        // 5. 缩小间隔
        interval = Math.floor(interval / 2)
    }

    return arr
}

继承

原型链继承

function Parent(){
  this.name = '邬坤源',
  this.play = [1,2,3]
}

function Child(){
  this.age = 29
}

Child.prototype = new Parent();

let myChild = new Child();

console.log(myChild.name);

// 缺点:改变s1的play属性,会发现s2也跟着发生变化了,这是因为两个实例使用的是同一个原型对象,内存空间是共享的

var s1 = new Child();
var s2 = new Child();
s1.play.push(4);
console.log(s1.play, s2.play); // [1,2,3,4]

构造函数继承

function Parent(){
  this.name = 'parent1';
}

Parent.prototype.getName = function () {
  return this.name;
}

function Child(){
  Parent.call(this);
  this.type = 'child'
}

let child = new Child();

console.log(child);

// 缺点 :父类原型对象中一旦存在父类之前自己定义的方法,那么子类将无法继承这些方法
console.log(child.getName());

组合继承(原型链继承 + 构造函数继承)

// 组合式继承就是把原型链继承和函数式继承结合起来

function Parent3 () {
  this.name = 'parent3';
  this.play = [1, 2, 3];
}

Parent3.prototype.getName = function () {
  return this.name;
}

function Child3() {
  // 第二次调用 Parent3()
  Parent3.call(this);
  this.type = 'child3';
}


// 第一次调用 Parent3()
Child3.prototype = new Parent3();

// 手动挂上构造器,指向自己的构造函数
// Child3.prototype.constructor = Child3;
var s3 = new Child3();
var s4 = new Child3();
s3.play.push(4);
console.log(s3.play, s4.play);  // 不互相影响
console.log(s3.getName()); // 正常输出'parent3'
console.log(s4.getName()); // 正常输出'parent3'

原型式继承

这里主要借助Object.create方法实现普通对象的继承

let parent = {
  name: 'li',
  friends: ['ha','mo','gui'],
  getName:function(){
    return this.name;
  }
}

let person = object.create(parent);
person4.name = "tom";
person4.friends.push("jerry");
console.log(person4.name); // tom
console.log(person4.name === person4.getName()); // true


let person5 = Object.create(parent4);
person5.friends.push("lucy");
console.log(person5.name); // parent4

console.log(person4.friends); // ["p1", "p2", "p3","jerry","lucy"]
console.log(person5.friends); // ["p1", "p2", "p3","jerry","lucy"]

  // 缺点:因为Object.create方法实现的是浅拷贝,多个实例的引用类型属性指向相同的内存,存在篡改的可能

寄生式继承

let parent5 = {
  name: "parent5",
  friends: ["p1", "p2", "p3"],
  getName: function() {
      return this.name;
  }
};

function clone(original) {
  let clone = Object.create(original);
  clone.getFriends = function() {
      return this.friends;
  };
  return clone;
}

let person5 = clone(parent5);

console.log(person5.getName()); // parent5
console.log(person5.getFriends()); // ["p1", "p2", "p3"]

组合寄生式继承

function Parent6() {
  this.name = 'parent6';
  this.play = [1, 2, 3];
}
Parent6.prototype.getName = function () {
  return this.name;
}
function Child6() {
  Parent6.call(this);
  this.friends = 'child5';
}

function clone (parent, child) {
  // 这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程
  child.prototype = Object.create(parent.prototype);
  child.prototype.constructor = child;
}

clone(Parent6, Child6);

Child6.prototype.getFriends = function () {
  return this.friends;
}

let person6 = new Child6();
console.log(person6); //{friends:"child5",name:"child5",play:[1,2,3],__proto__:Parent6}
console.log(person6.getName()); // parent6
console.log(person6.getFriends()); // child5

ES6 继承

class Person {
  constructor(name) {
    this.name = name
  }
  // 原型方法
  // 即 Person.prototype.getName = function() { }
  // 下面可以简写为 getName() {...}
  getName = function () {
    console.log('Person:', this.name)
  }
}
class Gamer extends Person {
  constructor(name, age) {
    // 子类中存在构造函数,则需要在使用“this”之前首先调用 super()。
    super(name)
    this.age = age
  }
}
const asuna = new Gamer('Asuna', 20)
asuna.getName() // 成功访问到父类的方法

算法题

大数相加

/*
    大数相加的意思是超过 JS 存放数据的安全范围(一般指的是数字)的数字进行相加
*/

console.log(Number.MAX_SAFE_INTEGER) //9007199254740991
console.log(Number.MIN_SAFE_INTEGER) //-9007199254740991

// 9007199254740991 + 1234567899999999999

let a = "9007199254740991", b = '1234567899999999999'

function add(a, b) {
    // 位数补全
    const MAX_LEN = Math.max(a.length, b.length)

    // padStart() 方法用于从字符串左侧填充 0
    a = a.padStart(MAX_LEN, 0)
    b = b.padStart(MAX_LEN, 0)

    let flag = 0 // 进位标志
    let str = '', j = MAX_LEN-1

    while(j >= 0) {
        let res = Number(a[j]) + Number(b[j]) + flag
        flag = res >= 10 ? 1 : 0
        res = res % 10
        str = res + str
        j--
    }

    // 处理最高位溢出
    if(flag === 1) {//增加多一位
        str = '1' + str
    }

    return str
}

// 正确结果:1243575099254740990
// 输出答案:1243575099254740990
console.log(add(a, b))

哈夫曼树

/*
    哈夫曼树 —— 最优二叉树
*/

/**
 * @param {*} val 
 * @param {*} left 
 * @param {*} right 
 */

function TreeNode(val, char, left, right) {
    this.val = val || 0  // 字符出现的次数
    this.char = char || '' // 待编码的字符(当前节点是叶子节点才给char赋值)
    this.left = left || null    
    this.right = right || null
}


/**
 * 
 * @param {Map} map 
 * @returns 
 */

function HuffmanTree(str) {
    if(str === '') { return null }

    //1. 统计字符出现的频率
    let hash = {}

    for(let i=0; i<str.length; i++) {
        hash[str[i]] ??= 0 // 前者为 null / undefined 才赋值
        hash[str[i]] = hash[str[i]] + 1
    }

    //2. 构造哈夫曼树
    const huffmanTree = this.getHuffmanTree(hash)
    console.log('===哈夫曼树===', huffmanTree)

    //3. 遍历哈夫曼树得到编码表
    const map = this.getHuffmanCode(huffmanTree)
    console.log('===哈夫曼编码表===', map)

    //4. 根据编码对照表,返回最终的二进制代码
    let res = ''
    for(let item in hash) {
        res += map.get(item)
    }
    console.log('===哈夫曼总编码===', res)
}

HuffmanTree.prototype.getHuffmanTree = function(hash) {
    // 构建叶子节点
    let forest = []
    for(let char in hash) {
        const node = new TreeNode(hash[char], char)
        forest.push(node)
    }

    console.log(forest)
    
    let allNodes = []
    while(forest.length != 1) {
        forest.sort((a, b) => a.val - b.val)
        let node = new TreeNode(forest[0].val + forest[1].val)
        allNodes.push(forest[0])
        allNodes.push(forest[1])
        node.left = allNodes[allNodes.length - 2] // 左子树放置词频低的
        node.right = allNodes[allNodes.length - 1] // 右子树放置词频高的

        forest = forest.slice(2)
        forest.push(node) // 将新生成的节点放入森林中
    }

    return forest[0] // 整棵树的根节点
}

// 树的遍历(只统计子结点)
HuffmanTree.prototype.getHuffmanCode = function(huffmanTree) {
    let map = new Map()

    // 层数大于二才有路径
    const search = (node, curPath) => {
        if(!node) { return }
        if(!node.left && !node.right) {
            map.set(node.char, curPath)
        }

        if(node.left) {
            search(node.left, curPath + '0')
        }
        if(node.right) {
            search(node.right, curPath + '1')
        }
    }

    search(huffmanTree, '')
    return map
}


const huff = new HuffmanTree('ABBCCCDDDDEEEEE')

千分位分隔符

/*
    实现对数字进行千位分隔符的分隔
    19,351,235.235767
*/


// 将数字转为字符串,返回的是字符串
var throusandDot = function(num) {
    num = String(num)
    let [zheng, xiao] = num.split('.') // 切成整数部分和小数部分

    console.log(zheng, xiao)
    
    let sum = 0, res = []
    for(let i=zheng.length-1; i>=0; i--) {
        res.push(zheng[i])
        sum++
        if(sum === 3 && i!=0) { res.push(','); sum = 0 }
    }

    return res.reverse().join('') + '.' + xiao
}

console.log(throusandDot(119351235.235767))



/*
    直接使用 api => 可能出现的问题是位数比较多的时候会被截取
*/
var throusandDot = function(num) {
    return num.toLocaleString()
}

console.log(throusandDot(119351235.235767))


/*
使用正则表达式
https://www.runoob.com/regexp/regexp-syntax.html
*/
var throusandDot = function(num) {
    var res=num.toString().replace(/\d+/, function(n){ // 先提取整数部分
        return n.replace(/(\d)(?=(\d{3})+$)/g, function($1){ //?= 匹配的是前面的内容 
            // console.log('$1', $1)
           return $1+",";
         });
   })
   return res;
}



console.log(throusandDot(119351235.235767))

最大公约数

/*
    求最大公约数
    1. 辗转相除法
    2. 更相减损法
    3. 普通解法
*/


// 辗转相除法
function greatestCommonDivisor(a, b) {
    if(b == 0) {
        return a
    }
    return greatestCommonDivisor(b, a % b)
}

// 更相减损法
function greatestCommonDivisor2(a, b) {
    if(a > b) {
        a -= b
    } else if(a < b) {
        b -= a
    } else {
        return a
    }
}

// 普通解法

更多算法实现可移步我的 GitHub,欢迎 start
https://github.com/tomato-wu/JS-algorithm.git

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【小番茄夫斯基】全网最全前端面试手撕算法题,原理手写汇总 的相关文章

随机推荐

  • 信息系统项目管理-信息化和信息系统-一

    一 信息资源日益成为重要生产要素 无形资产和社会财富 xff0c 被认为是与土地 能源 材料同等重要的战略资源 二 信息论 与控制论 系统论并称为现代科学的三论 三 信息系统突出的三大系统特性开放性 脆弱性 健壮性 四 管理模型是指系统服务
  • java中的异常处理

    异常概述 异常的作用 xff1a 增强程序的健壮性 java中异常以什么形式存在 xff1f 异常在java中以类的形式存在 xff0c 每一个异常类都可以创建异常对象 JVM执行到某一处觉得有异常 xff0c 会new异常对象 xff0c
  • 人工智能在医学影像中的研究与应用

    人工智能在医学影像中的研究与应用 韩冬 李其花 蔡巍 夏雨薇 宁佳 黄峰 沈阳东软医疗系统有限公司 xff0c 辽宁 沈阳 110167 慧影医疗科技 xff08 北京 xff09 有限公司 xff0c 北京 100192 东软集团股份有限
  • 开始

    文章目录 徐工本科生 希望明天更好 xff0c 今天开始扬帆起航 新的改变功能快捷键合理的创建标题 xff0c 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中 居左 居右
  • Linux-生产者消费者模型

    生产者消费者模型 生产者消费者模型概念生产者消费者模型特点生产者消费者模型优点基于BlockingQueue的生产者消费者模型基于阻塞队列的生产者消费者模型 模拟实现生产者消费者模型多生产者和多消费者 生产者消费者模型概念 生产者消费者模型
  • Ubuntu20.04下更新系统Python版本

    起因 xff1a 写Python时报错 xff1a TypeError unsupported operand type s for 61 dict and dict 原因 xff1a python3 9 支持对 dict 类型使用 xff
  • Ubuntu密码忘记怎么办

    1 重启Ubuntu xff0c 长按shift出现以下界面 xff0c 按回车键 2 紧接着进入如下界面 xff0c 选中recovery mode的选项 xff0c 按 e 进入界面 xff0c 务必记得不要按enter键 3 找到下图
  • 小程序视频截gif_3个简单的应用程序,可让您深入视频和GIF

    小程序视频截gif Deepfakes make it possible to manipulate videos and GIFs The technology has become so easy to use you can now
  • Spring框架详解(建议收藏)

    1 什么是Spring xff1f 官网 xff1a https spring io 侠义的Spring是指Spring框架 xff08 Spring Fremework xff09 https spring io projects spr
  • Debian (Linux)安装UFW防火墙

    Debian Linux 安装UFW防火墙 1ufw简介 UFW xff0c 即简单防火墙 xff0c 是iptables的接口 xff0c 旨在简化防火墙的配置过程 尽管iptables是可靠且灵活的工具 xff0c 但对于初学者而言 x
  • 高性能动画JSON动画

    animejs 它是一个js动画库 xff0c 是对transform进行封装 xff0c 使其受js控制 拥有更高性能和很好的兼容 最重要的是 xff1a 提供了很多回调 监听方法 eg 每帧回调 每次循环回调 循环开始的回调 提供了一个
  • C++ 生产者消费者示例代码

    三部分构成 xff1a 生产者 消费者 仓储 span class token macro property span class token directive keyword include span span class token
  • 7-1 将数组中的数逆序存放 (15 分)

    7 1 将数组中的数逆序存放 15 分 本题要求编写程序 xff0c 将给定的n个整数存入数组中 xff0c 将数组中的这n个数逆序存放 xff0c 再按顺序输出数组中的元素 输入格式 输入在第一行中给出一个正整数n xff08 1 n 1
  • JavaFX学习笔记(最全,最详细)

    文章目录 Java JavaFX桌面GUI开发1 基本概念2 最小框架代码3 控件布局4 xff0c 初步认识stage窗口5 xff0c stage窗口模式 StageStyle 6 xff0c screen类的使用7 xff0c Gro
  • vue3安装和开发环境搭建

    文章目录 一 xff0c 简介二 xff0c vue cil 搭建 vue3 开发环境三 xff0c 增加typescipt 一 xff0c 简介 二 xff0c vue cil 搭建 vue3 开发环境 1 xff0c 安装 xff1a
  • 使用vite创建vue项目和使用vue-cli创建项目的区别

    文章目录 一 xff0c 介绍二 xff0c vite创建项目介绍三 xff0c vue cli创建项目介绍 xff08 1 xff09 安装升级 xff08 2 xff09 创建项目 一 xff0c 介绍 Vite 是一个 web 开发构
  • vue3中的组件通信【2】《爷孙组件通信》

    文章目录 爷孙组件通信provide inject响应性数据的传递与接收 爷孙组件通信 顾名思义 xff0c 爷孙组件是比 父子组件通信 要更深层次的引用关系 xff08 也有称之为 隔代组件 xff09 xff1a Grandfather
  • 大前端知识图谱+B站视频整合

    文章目录 前端学习路径B站视频整合网络知识超文本标记语言层叠样式表浏览器脚本语言 https www bilibili com video BV1Sy4y1C7ha https www bilibili com video BV1Sy4y1
  • 电台复活节_如何玩Android 11的隐藏复活节彩蛋游戏

    电台复活节 Justin Duino 贾斯汀 杜伊诺 Justin Duino Google includes a hidden Easter Egg with each new Android version Android 11 has
  • 【小番茄夫斯基】全网最全前端面试手撕算法题,原理手写汇总

    文章目录 深拷贝柯里化函数实现 instanceof手写 new数组去重flat 拍平数组ObjectDefineProperty实现双向数据绑定setInterval 实现 setTimeoutsetTimeout 实现 setInter