记忆中常考手写题

1.柯里化

function argsSum(args) {
  return args.reduce((pre, cur) => {
    return pre + cur
  })
}
function add(...args1) {
  let sum1 = argsSum(args1)
  let fn = function (...args2) {
    let sum2 = argsSum(args2)
    return add(sum1 + sum2)
  }
  fn.toString = function () {
    return sum1
  }
  return fn
}

2.手写 instanceof

思路:a 沿着原型链找到 b.prototype,则 a instanceof b = true,遍历 a 的原型链,找到 b.prototype,返回 true,否则返回 false

const my_instanceof = (A, B) => {
  let p = A //指针指向a
  while (p) {
    //遍历原型链
    if (p === B.prototype) {
      return true
    }
    p = p.__proto__
  }
  return false
}

3.深克隆

function clone(data) {
  if (typeof data === 'symbol') {
    //symbol,symbol是非object的基本类型
    return Symbol().for(data.description)
  } else if (typeof data != 'object') {
    //基本类型
    return data
  } else if (data instanceof Array) {
    // Array
    return data.map(i => clone(i))
  } else if (data.constructor === Object) {
    //避免 new Date,处理json
    let res = {}
    for (let key in data) {
      res[key] = clone(data[key])
    }
    return res
  } else {
    //系统对象及自定义对象 类似于class
    return new data.constructor(data)
  }
}

4.手写bind

function _bind(asThis) {
  var fn = this //记录this
  var args = slice.call(arguments, 1)
  if (typeof fn != 'function') {
    throw new Error('bind需使用在函数上')
  }
  function resFn() {
    var args2 = slice.call(arguments, 0)
    return fn.apply(
      resFn.prototype.isPrototypeOf(this) ? this : asThis,
      args.concat(args2))
  }
  resFn.prototype = fn.prototype 
  return resFn
}

5.手写new

function new_operator(_constructor, ...args) {
  // ① 创建新对象obj,并关联obj原型到构造函数原型对象上
  let obj = Object.create(_constructor.prototype)
  // ② 执行构造函数,且绑定this到新对象Obj上,实现继承。同时接受返回值res
  let res = _constructor.apply(obj, args)
  // ③ 返回值判断
  return res instanceof Object ? res : obj
}

6.手写Promise.race

Promise.myRace = arr => {
  return new Promise((resolve, reject) => {
    arr.forEach(p => p.then(resolve, reject))
  })
}
//Promise.any(谁先成功)比Promise.race(谁先完成)好用

7.手写Promise.all

Promise.myall = promises => {
  let complete = 0
  let result = []
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(res => {
        complete++
        result[i]= res
        if (complete == promises.length) {
          resolve(result)
        }
      }, reject)
    }
  })
}

8.(京东快手)两数之和

示例:nums = [2,7,11,15] target = 9 //输出[0,1]
思路:nums 去相亲者,target 匹配的条件,字典建立一个介绍所储存相亲者的数字和下标

//obj解法
let nums = [2, 7, 11, 15],
  target = 9;
function Two(nums, target) {
  const obj = {}
  for (let i = 0; i < nums.length; i++) {
    let a = nums[i]
    let b = target - a
    if (obj[b] != undefined) {
      return [obj[b], i]
    } else {
      obj[a] = i
    }
  }
  return null
}
//时间复杂度和空间复杂度都是O(n)
//Map解法
var twoSum = function (nums, target) {
  let map = new Map()
  for (let i = 0; i < nums.length; i++) {
    const n = nums[i]
    const n2 = target - n // 符合匹配条件的选手
    if (map.has(n2)) {
      return [map.get(n2), i] // 返回符合条件对象的下标,自身下标
    } else {
      map.set(n, i)
    }
  }
}
//时间复杂度 O(n)//空间复杂度 O(n)//线性

9. 两个数组的交集 题号 349

Map 解题思路,新建立一个字典,遍历 nums1,填充字典,遍历 nums2,遇到字典值就选出,并从字典里删除

var intersection = function (nums1, nums2) {
  const map = new Map()
  nums1.forEach(n => {
    map.set(n, true) //代表这个值在字典里存在
  })
  let res = []
  nums2.forEach(n => {
    if (map.get(n)) {
      res.push(n)
      map.delete(n)
    }
  })
  return res
}
//时间复杂度O(n+m)
//空间复杂度指临时变量内存消耗 O(m)

10.拍平数组,去除重复部分,得到升序不重复数组,[[1,2,2],[3,4,5,5],[6,7,8,9[11,12,[12,13,[14]]]],10]

flat1(arr5)
function flat1(a) {
  let res = []
  let json = {}
  //拍平并去重
  for (let i = 0; i < a.length; i++) {
    if (typeof a[i] == 'number') {
      // if(!res.includes(a[i])){//低性能版
      //   res.push(a[i])
      // }
      if (!json[a[i]]) {
        //高性能
        res.push(a[i])
        json[a[i]] = true
      }
    } else {
      flat1(a[i])
    }
  }
}

11.爬楼梯 70 dp问题

定义子问题f(n) = f(n-1) + f(n-2)
反复执行 从2循环到n,执行上述公式

var clibStairs2 = function (n) {
  if (n < 2) {
    return 1
  }
  let dp0 = 1
  let dp1 = 1
  for (let i = 2; i < n; i++) {
    const tmp = dp0
    dp0 = dp1
    dp1 = dp1 + tmp 
  }
  return dp1
}
//时间复杂度 o(n)
//空间复杂度 o(n)                   

12.变态版青蛙跳台阶 dp问题

function jump(n){
  if(n<0){
    return -1
  }else if(n==1){
    return 1
  }else{
    return 2*jump(n-1)
  }
}

13. 环形链表,题号 141

解题思路:有一快一慢两个指针遍历链表,指针可以相逢,说明有环,返回 true,两个指针不相逢就说明没有环,返回 false

var hasCycle = function (head) {
  let p1 = head //慢指针
  let p2 = head //快指针
  while (p1 && p2 && p2.next) {
    p1 = p1.next //走一步
    p2 = p2.next.next //走两步
    if (p1 === p2) {
      //两个指针是否重逢
      return true
    }
  }
  return false
}
//有while循环,时间复杂度 O(n)
//空间复杂度:O(1)。因无线性增长结构,矩阵,列表

14.旋转数组 189

function shift(arr, k) {
  k %= arr.length
  if (k >= Math.floor(arr.length / 2)) {
    arr.push(...arr.splice(0, arr.length - k))
  } else {
    arr.unshift(...arr.splice(arr.length - k, k))
  }
  return arr
}

15.实现 sleep 函数,等待 1000ms,可以从 promise、generator、async 角度实现,本意问实现 promise

function sleep(ms) {
  return new Promise(resolve => {
    setTimeout(resolve, ms)
  })
}
;(async () => {
  console.log(11)
  await sleep(2000)
  console.log(22)
})()

你可能感兴趣的:(记忆中常考手写题)