看了涡流大佬的面试文章的总结(手撕代码 & 算法)

简介: 看了涡流大佬的面试文章的总结(手撕代码&算法)

手写深拷贝


function deepClone(obj) {
  let newObj = {};
  if(typeof obj !== "object" || obj == null) {
    return obj;
  }
  for(let key in obj) {
    if(typeof obj[key] !== "object") { // 基本类型加function
      newObj[key] = obj[key];
    }else {
      if(isType(obj[key]) == "Array") { // 判断数组
        let newArray = [];
        for(let index in obj[key]) { // 递归调用,然后需要返回当前非对象的值,然后加入
          newArray[index] = deepClone(obj[key][index])
        }
        newObj[key] = newArray;
      }else { // 对象类型
        let newObject = {};
        for(let newKey in obj[key]) {
          newObject[newKey] = deepClone(obj[newKey]);
        }
      }
    }
  }
  return newObj;
}
function isType(value) {
  const type = Object.prototype.toString.call(value);
  switch (type) {
    case "[object Array]":
      return "Array"
    case "[object Object]":
      return "Object"
    default:
      return typeof value;
  }
}


以前写过一篇文章


手写节流和防抖


以前写过一篇文章还是比较全的,感谢coderwhy老师


手写call / apply / bind


简单的实现


  • 思路就是获取当前调用的函数,然后将其作为当前指定的this属性值。为了避免覆盖当前this对象的已有属性,那么将设置symbol值作为属性名。其他的都是一些边界判断。


const myCall = function (context, ...args) {
      let func = this
      context = context ||  window
      if (typeof func !== 'function') throw new TypeError('this is not a function')
      let caller = Symbol('caller')
      context[caller] = func
      let res = context[caller](...args)
      delete context[caller]
      return res
    }
    Function.prototype.myCall = myCall


function myApply(context, arr) {
      let func = this;
      context = context || window;
      if (typeof func !== 'function') throw new TypeError('this is not a function')
      //唯一的键值
      let caller = Symbol('caller')
      context[caller] = func
      //函数返回值
      let res;
      if (!arr) {
        res = context[caller]()
      } else {
        res = context[caller](...arr)
      }
      //删除该函数
      delete context[caller]
      return res
    }
Function.prototype.myApply = myApply;


function myBind(context, ...args) {
  const fn = this;
  if(typeof fn !== "function") throw new TypeError("this is not function");
  context = context || window;
  // 因为bind需要返回一个函数,然后利用call、apply改变this即可。并传入参数。
  return function(...args2){
    fn.call(context, ...args,...args2)
  };
}
Function.prototype.myBind = myBind


手写Promise.all / Promise.race / Promise.allSettled


完整的promise实现,请看以前写的一篇文章


实现它,我们必须的知道他们的作用是啥?


  • all:如果传入的promises全部都变成fulfilled,那么promise的状态将变为fulfilled。如果有一个promises状态变为rejected,那么promsie状态将变为rejected。


function all(promises) {
  return new Promise((resolve, reject) => {
    let resArr = [];
    for(let promise of promises) {
      promise.then(res => { 
        resArr.push(res);
        if(resArr.length === promises.length) { // 每次成功都需要判断
          resolve(resArr)
        }
      })
      promise.catch((err) => {
        reject(err)
      })
    }
  })
}


  • race: 传入的promises最先改变状态的promise决定当前的promise状态。


function race(promises) {
  return new Promise((resolve, reject) => {
    for(let promise of promises) {
      promise.then(res => { 
        resolve(res)
      })
      promise.catch((err) => {
        reject(err)
      })
    }
  })
}


  • allSettled: 当传入的promises的状态全部都变化后,promise的状态变为fulfilled。


function allSettled(promises) {
      return new Promise((resolve) => {
        let resArr = []
        for(let promise of promises) {
          promise.then(res => { 
            resArr.push({
              status: "fulfilled",
              value: res
            })
            if(resArr.length === promises.length) {
              resolve(resArr)
            }
          })
          promise.catch((err) => {
            resArr.push({
              status: "rejected",
              value: err
            })
            if(resArr.length === promises.length) { // 可能promise有异步任务,所以每一次状态改变都需要判断
              resolve(resArr)
            }
          })
        }
      })
    }


手写括号匹配


不知道是不是LeetCode-20。如果是的话,这一题使用栈的思想最好理解。


以前写过一篇文章


数组去重


  • 通过set特点实现。


// set数据结构
    Array.from(new Set(arr))
    [...new Set(arr)]


  • 通过对象键名不能重复实现。


// 利用对象的键不能重复的特点
    function removeDup(arr) {
      const obj = {}
      arr.forEach((item) => {
        if(!obj[item]) {
          obj[item] = true
        }
      })
      return Object.keys(obj)
    }


将奇数排在前面,偶数排在后面。要求时间复杂度O(n)。空间复杂度O(1)(不能用splice)


不知道这一题是不是这个意思。


function oddEven(arr) {
  // 先排序,这个排序算法可以自己去查询时间复杂度为o(n)的算法。
  arr = arr.sort((a, b) => {
    return a - b;
  })
  const odd = []; // 奇数
  const even = []; // 偶数
  for(let item of arr) {
    if(item % 2 === 0) { // 偶数
      even.push(item)
    }else { // 奇数
      odd.push(item)
    }
  }
  return [...odd, ...even]
}


解析出URL中所有的部分


通过URL类解析出来的是这个样子,我们只需要处理一下searchParams和protocol即可


网络异常,图片无法展示
|


function parseUrl(url) {
  const resUrlObj = new URL(url);
  // console.log(resUrlObj)
  const params = {}
  const resObj = {};
  // 处理查询参数
  for(let [key, value] of resUrlObj.searchParams) {
    params[key] = value
  }
  for(let key in resUrlObj) {
    if(key == "protocol") { // 处理协议
      resObj[key] = resUrlObj[key].slice(0, (resUrlObj[key].length - 1))
    }else {
      resObj[key] = resUrlObj[key]
    }
  }
  return {...resObj, searchParams: params}
}


实现一个compare函数,比较两个对象是否相同


这里的比较应该不是值广义的地址,而是指对象的属性和值。


function compare(obj1, obj2) {
  const obj1Keys = Object.keys(obj1);
  const obj2Keys = Object.keys(obj2);
  if(obj1Keys.length !== obj2Keys.length) return false;
  for(let key of obj1Keys) {
    if(!obj2Keys.includes(key)) {
      return false;
    }else {
      if(typeof obj1[key] === "object" || typeof obj2[key] === "object") { // 递归调用,
        // 注意:这里也可以判断数组,Object.keys([1,2,3]) => ["0", "1", "2"]
        if(!compare(obj1[key], obj2[key])) return false;
      } else {// 基本类型
        if(obj1[key] !== obj2[key]) return false;
      }
    }
  }
  return true;
}


柯里化


是把接收多个参数的函数,变成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数,而且返回结果的新函数的技术。


实现思路


  • 我们知道函数的length属性是判断形参的个数。


  • 判断不断调用的函数传入的中参数是否大于等于函数的形参。


  • 如果大于等于,就直接调用该函数,并传入参数


  • 如果小于,那就再返回一个函数,并且内部返回递归调用的函数。


function curry(fn, ...args1) {
      // 获取形参的个数
      const length = fn.length;
      const resFn = function(...args2) {
        const totalArgs = [...args1, ...args2];
        if(totalArgs.length >= length) {
          // return resFn;
          fn.call(this, ...totalArgs)
        }else { // 参数还没有传完
          return function(...args3) {
            return resFn.call(this, ...args2, ...args3)
          }
        }
      }
      return resFn
    }


中划线转大写


function lineChangeUpperCase(str) {
      // 先依据_分割字符串
      const strArr = str.split("_");
      // 利用map映射将每个短横线后面的字符转大写
      return strArr.map((item, index) => {
        if(index === 0) {
          return item;
        }else {
          return item.slice(0, 1).toUpperCase() + item.slice(1)
        }
      }).join("")
    }


千位分割


以前写过一篇文章


使用es5实现es6的let关键字


利用自执行函数


// 下面代码不存在块级作用域
    for(var i = 0; i < 5; i++) {
      setTimeout(() => {
        console.log(i); //  5  5  5  5  5
      }, 0)
    }
    // let解决的问题
    for(let i = 0; i < 5; i++) {
      setTimeout(() => {
        console.log(i); //  0 1 2 3 4 
      }, 0)
    }
    // 立即执行函数代替let
    for(var i = 0; i < 5; i++){
      (function(a){
        setTimeout(() => {
          console.log(a); //  0 1 2 3 4 
        }, 0)
      })(i)
    }


查找数组中的重复元素


  • 双重for循环


function getRepeatElement(arr) {
      let resArr = []
      for(let i = 0; i < arr.length; i++) {
      // for(let i  in arr) { // 为什么for in 不正确
        for( let j = i + 1; j < arr.length; j++) {
          if(arr[i] == arr[j]) {
            resArr.push(arr[i])
          }
          continue;
        }
      }
      return resArr 
    }


  • 数组中判断数组中方法(includes, indexOf)实现。


// indexOf / includes实现
    function getRepeatElement1(arr) {
      let resArr = []
      for(let i = 0; i < arr.length; i++) {
        let copyArr = [...arr]
        let item = arr[i];
        copyArr.splice(i, 1);
        if(copyArr.includes(item)) {
        // if(copyArr.indexOf(item) !== -1) {
          resArr.push(item)
        }
      }
      return resArr //[5, 3, 4, 4]
    }


  • 先进行排序,然后再通过比较相邻元素的方式。


// 先排序,然后再比较相邻元素。
    function getRepeatElement3(arr) {
      let resArr = []
      copyArr = arr.sort();
      for(let i = 0; i < arr.length - 1; i++) {
        if(arr[i] === arr[i + 1]) {
          resArr.push(arr[i]);
        }
      }
      return resArr
    }


数组乱序


  • 通过sort结合Math.random()。


// 该方法有缺陷,大多数元素的位置是不变的
    function mixArr(arr) {
      return arr.sort(() => Math.random() - 0.5)
    }


  • 洗牌算法


// 洗牌算法
    function shunflee(arr) {
      const len = arr.length
      while(len > 1) {
        const index = parsetInt(Math.random() * len--)
        [arr[index], arr[len]] = [arr[len], arr[index]]
      }
      return arr
    }


相关文章
|
24天前
|
机器学习/深度学习 算法 PyTorch
RPN(Region Proposal Networks)候选区域网络算法解析(附PyTorch代码)
RPN(Region Proposal Networks)候选区域网络算法解析(附PyTorch代码)
179 1
|
1月前
|
算法 安全 C语言
使用C语言实现DES算法代码
使用C语言实现DES算法代码
|
1月前
|
开发框架 算法 搜索推荐
C# .NET面试系列九:常见的算法
#### 1. 求质数 ```c# // 判断一个数是否为质数的方法 public static bool IsPrime(int number) { if (number < 2) { return false; } for (int i = 2; i <= Math.Sqrt(number); i++) { if (number % i == 0) { return false; } } return true; } class Progr
58 1
|
9天前
|
负载均衡 算法 应用服务中间件
面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
字节跳动面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
27 0
|
15天前
|
机器学习/深度学习 算法 搜索推荐
Machine Learning机器学习之决策树算法 Decision Tree(附Python代码)
Machine Learning机器学习之决策树算法 Decision Tree(附Python代码)
|
1月前
|
机器学习/深度学习 算法 Python
傅里叶变换算法和Python代码实现
傅立叶变换是物理学家、数学家、工程师和计算机科学家常用的最有用的工具之一。本篇文章我们将使用Python来实现一个连续函数的傅立叶变换。
29 8
|
25天前
|
存储 机器学习/深度学习 算法
C语言代码实现数据结构与算法
以上代码中,哈希表使用链表解决哈希冲突,每个链表节点包含一个键值对。hash函数用于计算键值对应的哈希值,insert函数用于向哈希表中插入一个键值对,若当前位置为空,则直接插入;否则,将新节点插入到链表末尾。search函数用于在哈希表中查找指定键值的值,若存在则返回其值,否则返回-1。
32 1
|
27天前
|
算法
覃超老师 算法面试通关40讲
无论是阿里巴巴、腾讯、百度这些国内一线互联网企业,还是 Google、Facebook、Airbnb 等硅谷知名互联网公司,在招聘工程师的过程中,对算法和数据结构能力的考察都是重中之重。本课程以帮助求职者在短时间内掌握面试中最常见的算法与数据结构相关知识点,学会面试中高频算法题目的分析思路,同时给大家从面试官的角度来分析算法题的解答技巧,从而更有效地提升求职者的面试通过率。
15 3
覃超老师 算法面试通关40讲
|
1月前
|
存储 算法 网络协议
通过一篇文章让你了解数据结构和算法的重要性
数据结构和算法的重要性,不仅仅在于它们在计算机科学领域中的核心地位,更在于它们对于解决实际问题、优化系统性能、提升软件开发效率等方面的深远影响。在现代信息技术的浪潮中,数据结构和算法如同计算机的“灵魂”,指导着信息的有序存储和高效处理。
44 0
|
1月前
|
存储 算法
【数据结构与算法】【腾讯阿里链表面试题】算法题--链表易懂版讲解
【数据结构与算法】【腾讯阿里链表面试题】算法题--链表易懂版讲解