几个常见的手写编程题

161 阅读4分钟

1、实现一个方法,可以从一个对象中批量获取属性

const obj = { selector: { to1: { toutiao: "FE Coder" } }, target: [1, 2, { name: 'byted' }, [3,4]] }
console.log(getValueByStr(obj, `target[2][${'name'}]`, `selector[${'to' + 1}].toutiao`))
// 输出[ 'byted', 'FE Coder' ]

function getValueBykey(data, pathStr) {
    const pathList = pathStr.split('.')
    return pathList.reduce((p, n) => {
        if (/\[\w+\]/.test(n)) {
            const keyList = splitMatchKey(n)
            return keyList.reduce((pre, next) => {
                return pre[next]
            }, p)
        }
        return p[n]
    }, data)
}
function splitMatchKey(str) {
    return str.split(/\[(\w+)\]/).filter(item => item)
}
function  getValueByStr(data, ...args) {
    return args.reduce((pre, next) => {
        pre.push(getValueBykey(data, next))
        return pre
    }, [])
}

2、实现add函数var ans = add(1)(2)(3)(4)...,console.log(ans)//输出1+2+3+4+...之和

function add(a) {
    var temp = function (b) { return add(a + b) }
    temp.valueOf = temp.toString = function () { return a }
    return temp
  }

3、01背包问题

/**背包总体积:8
 * [2, 3, 4, 5] weigth // 体积
 * [3, 4, 5, 6] worth // 价值
 */
 动态规划解法
const weightList = [2, 3, 4, 5, 6, 7, 8, 9, 10] // 物品所占体积
const worthList = [3, 4, 5, 6, 7, 8, 9, 10, 11]
let maxWorthArray = new Array(9).fill(new Array(9))
function getMaxWorth(weightSum, skuIndex) {
    let maxWorth = 0
    if (maxWorthArray[weightSum] && maxWorthArray[weightSum][skuIndex]) {
        maxWorth = maxWorthArray[weightSum][skuIndex]
    } else if (skuIndex == 0) {
        if (weightSum >= weightList[skuIndex]) {
            maxWorth = worthList[skuIndex]
        } else {
            maxWorth = 0
        }
    } else if (weightSum >= weightList[skuIndex]) {
        maxWorth = Math.max(getMaxWorth(weightSum - weightList[skuIndex], skuIndex - 1) + worthList[skuIndex], getMaxWorth(weightSum, skuIndex - 1))
    } else {
        maxWorth = getMaxWorth(weightSum, skuIndex - 1)
        maxWorthArray[weightSum][skuIndex] = maxWorth
    }
    return maxWorth
}

贪心算法
function greed(values, weights, capacity) {
    let len = values.length
    const ratioList = values.reduce((pre, next, index) => {
        pre.push({
            worth: next,
            weight: weights[index],
            ratio: (next/weights[index]).toFixed(1)
        })
        return pre
    }, [])
    ratioList.sort((a, b) => {
        return b.ratio - a.ratio
    })
    console.log(ratioList)
    let maxWorth = 0
    let remainRoom = capacity
    for (let i = 0; i < len; i++) {
        if (remainRoom > 0 && ratioList[i].weight <= remainRoom) {
            // let num = Math.floor(remainRoom / ratioList[i].weight)
            maxWorth += ratioList[i].worth
            remainRoom -= ratioList[i].weight
        } else {
            break
        }
    }
    return maxWorth
}

4、给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 num1 成为一个有序数组 const nums1 = [8,9,10] const nums2 = [4, 5, 6]

function groupArray(array1, m, array2, n) {
  let len1 = m - 1
    let len2 = n - 1
    let len = m + n - 1
    while (len2 > -1) {
      if (len1 < 0 && len > 0) {
        array1[len--] = array2[len2--]
      }
      array1[len--] = array1[len1] > array2[len2] ? array1[len1 --] : array2[len2 --]
    }
    return array1
}

5、在一个数组中找出三数之和为target值,给定 nums = [2, 7, 9, 11, 15, 16], target = 28

function getSumNumber(array, target) {
  if (array.length <= 3) return array
  for (let index = 0; index < array.length - 2; index++) {
    let left = index + 1
    let right = array.length - 1
    while (left < right) {
      const sum = array[left] + array[right] + array[index]
      if (sum > target) {
        right --
      } else if(sum < target)  {
        left ++
      } else {
        return [array[index], array[left], array[right]]
      }
    }
  }
}

6、求最长无重复子串

function getMaxNoRepeatStr(str) {
  let left = 0
  let len = str.length
  let temp = {}
  let max = 0
  let maxStr = ''
  for (let i = 0; i < len; i++) {
    if (temp.hasOwnProperty(str[i])) {
      left = Math.max(temp[str[i]] + 1, left)
    }
    max = Math.max(max, i - left + 1)
    if (max > maxStr.length) {
      maxStr = str.substr(left, max)
    }
    temp[str[i]] = i
  }
  console.log(maxStr)
  return max
} 

7、给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效

function compare(str) {
  const leftToRight = {
      '(': ')',
      '{': '}',
      '[': ']'
  }
  const rightToLeft = {
      ')': '(',
      '}': '{',
      ']': '['
  }
  let stack = []
  for (let key of str) {
      if (leftToRight[key]) { // 如果是左括号直接插入
          stack.push(key)
      } else {
          const tail = stack.slice(-1).toString()
          if (rightToLeft[key] && rightToLeft[key] === tail) {
              stack.pop()
          } else {
              return false
          }
      }
  }
  return !stack.length
}

8、给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。

function getBetween(n, k) {
    if (n < k) {
        return []
    }
    let res = []
    function helper(index = 1, i, prev = []) {
        if ((prev.length + i) < k) {
            return
        }
        while (i) {
            if (index === k) {
                res.push([...prev, i])
            } else {
                helper(index + 1, i-1, [...prev, i])
            }  
            i--
        }
    }
    helper(1, n)
    return res
}

9、堆排序算法

function maxHeapify(arr, i, size) {
  let left, right, minlr = -1
  while (i < size) {
    left = 2*i
    right = left + 1
    if (left > size) {
      break
    }
    if (left <= size && right > size) { // 只有左节点
      minlr = left
    }
    if (left <= size && right <= size) { // 左右节点都有
      minlr = arr[left] > arr[right] ? right : left
    }
    if (arr[i] > arr[minlr]) {
      swap(arr, minlr, i)
      i = minlr
    } else {
      break
    }
  }
}
function swap(arr, i, j) {
  let temp = arr[j]
  arr[j] = arr[i]
  arr[i] = temp
}
function buildMaxHeap(arr) { // 构建小顶堆
  if (!Array.isArray(arr)) return []

  //将null插到数组第一个位置上
  arr.unshift(null)
  let lastParentIndex = Math.floor((arr.length - 1) / 2)
  for (let i = lastParentIndex; i > 0; i--) {
    maxHeapify(arr, i, arr.length - 1)
  }
  return arr
}
// 构建小顶堆,实现倒序
function sortArr(arrList) {
  buildMaxHeap(arrList)
  for (let i = arrList.length -1 ; i > 0; i--) {
    swap(arrList, 1, i)
    //重新调整小顶堆
    maxHeapify(arrList, 1, i - 1)
  }
  arrList.shift()
  return arrList
}
// 构建小顶堆实现topK算法
function topK(list, k) {
  let newStack = buildMaxHeap(list.slice(0, k))
  for (let i = k, len = list.length; i < len; i++) {
    if (newStack[1] < list[i]) {
      newStack[1] = list[i]
      maxHeapify(newStack, 1, k)
    }
  }
  newStack.shift()
  return newStack
}

10、koa中间件原理

class App {
    constructor() {
        this.mutationList = []
        this.index = 0
    }
    use(fn) {
        this.mutationList.push(fn)
    }
    compose() {
        const mutationList = this.mutationList
        // 递归函数
        function dispatch(index) {
            // 如果所有中间件都执行完跳出
            if (index === mutationList.length) return;
            // 取出第 index 个中间件并执行
            const route = mutationList[index];
            return route(() => dispatch(index + 1));
        }
        // 取出第一个中间件函数执行
        dispatch(0);
    }
    composeReduce() { // 使用reduce函数
        return this.mutationList.reduce((pre, n) => (args) => pre(() => n(args)))(() =>{})
    }
}

11、嵌套过滤器、拦截器的原理

function c(num) {
    return num + 'c'
}
function b(num) {
    return num + 'b'
}
function a(num) {
    return num + 'a'
}
function curry(...fns) {
    if (!fns) return
    return fns.reduce((pre, next) => {
        return (...rest) => next(pre(...rest))
    })
}
const test = curry(a, b, c)
console.log(test(1))// 输出1abc,按照顺序执行,前一个的执行结果是后一个函数的入参

12、写一个 mySetInterVal(fn, a, b), 每次间隔 a, a + b, a + 2b 的时间,然后写一个 myClear,停止上面的 mySetInterVal

function initInterval(fn, a, b) {
    let count = 0
    let timer = null
    function createInterval() {
        clearInterval(timer)
        timer =  setInterval(() => {
            fn()
            count++
            createInterval()
        }, a + count * b)
    }
    createInterval()
    return timer
}
const timer = initInterval(() => { console.log('执行代码') }, 2000, 500)

13、手写节流函数

function throttle(fn, timeout, immediate, trailCall) {
    let currentTime = 0
    let lastTime = 0
    let timer = null
    return function (...args) {
        let context = this
        currentTime = +new Date()
        if (timer) {
              clearTimeout(timer)
          }
          if (immediate) {
            immediate = false
            fn.call(context, ...args)
            lastTime = +new Date()
            return
          }
        if (currentTime - lastTime >= timeout) {
            fn.call(context, ...args)
            lastTime = currentTime
        }
        if (trailCall) {
          timer = setTimeout(() => {
            fn.call(context, ...args)
            lastTime = +new Date()
          }, timeout)
        }
    }
}

14、把一个数组,分为n组,每组的和尽可能的接近或相等

  /*
     * 数组排序
     * @arr 排序的数组
    */
   const arrSort = (arr) => {
    return arr.sort((a, b) => b - a)
  };
  /*
   * 数组求和
   * @arr 求和数组
  */
  const sumTotal = arr => eval(arr.join('+'));

  /*
   * getEqualArr 获取均分的结果
   * @arr 均分的整数数组
   * @n 均分的份数
  */
  const getEqualArr = (arr,n=3) => {
    const sortArr = arrSort(arr);
    const arrSum = sumTotal(arr);
    let result = [];
    (getEachArr = () => {
      let startNum = 0;
      let eactArr = [];
      // 如果是最后一组,就直接push
      if (result.length === n-1) {
        result.push(sortArr);
        return result;
      } else {
        sortArr.map((num, index) => {
          if (startNum + num <= Math.ceil(arrSum / n)) {
            startNum = startNum + num;
            eactArr.push(...sortArr.splice(index, 1));
          }
        })
        result.push(eactArr);
        // 提取完一组接着再进行提取下一组
        getEachArr();
      }
    })();
    return result;
  }
  console.log(getEqualArr([1, 2, 3, 4, 5, 6, 7, 8])) // 输出[ [ 8, 4 ], [ 7, 5 ], [ 6, 3, 2, 1 ] ]

15、常见的排序算法(冒泡、快排、归并排、插入排) blog.csdn.net/w405722907/…

// 使用快排实现topk算法
function quickTopK(arr, k) {
  if(k==0)return []
  if (arr.length < 2 || arr.length <= k) return arr
  let midValue = arr.splice(0, 1), left = [], right = []
  arr.forEach((el) => {
      el > midValue ? left.push(el) : right.push(el)
  });
  console.log(left, right)
  if (left.length == k) {
      return left
  } else if (left.length > k) {
      return quickTopK(left, k)
  } else {
      return left.concat(midValue, quickTopK(right, k - left.length - 1))
  }
}

16、手写promise实现

const PENDING = 'pending'
const FULFILL = 'fuifilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(executor) { // 传入一个回调函数
    	this._resolveQueue = []
    	this._rejectQueue = []
    	this._status = PENDING
    	this._value = ''
		const _resolveFn = value => {
  			setTimeout(() => { // 防止先执行回调再then收集依赖
  				if (this._status !== PENDING) return
  				this._value = value
				this._status = FULFILL
  				while(this._resolveQueue.length) {
						const cb = this._resolveQueue.shift()
  					cb(value)
  				}
  			})
  		}
  		const _rejectFn = value => {
				setTimeout(() => { // 防止先执行回调再then收集依赖
					if (this._status !== PENDING) return
					this._value = value
					this._status = REJECTED
					while(this._rejectQueue.length) {
							const cb = this._rejectQueue.shift()
						cb(value)
					}
				})
			}
  		executor(_resolveFn, _rejectFn)
    }
	then(resolveFn, rejectFn) { // 为了实现链式调用,所以then方法需要return一个promise对象
		typeof resolveFn !== 'function' ? resolveFn = value => value : null
        typeof rejectFn !== 'function' ? rejectFn = reason => {
        	throw new Error(reason instanceof Error? reason.message:reason);
    	} : null
    	return new MyPromise((resolve, reject) => {
    		const fuifilledFn = value => {
	    		try {
	    			const x = resolveFn(value)
	    			x instanceof MyPromise ? x.then(resolve) : resolve(x)
	    		} catch(error) {
	    			reject(error)
	    		}
	    	}
    		const rejectedFn = value => {
	    		try {
	    			const x = rejectFn(value)
	    			x instanceof MyPromise ? x.then(resolve) : resolve(x)
	    		} catch(error) {
	    			reject(error)
	    		}
	    	}
	    	switch(this._status) {
				case PENDING:
	    		this._resolveQueue.push(fuifilledFn)
    			this._rejectQueue.push(rejectedFn)
    			break;
    			case FULFILL:
    			fuifilledFn(this._value)
    			break;
    			case REJECTED:
    			rejectedFn(this._value)
	    	}
    	})
    }
}

17、sku算法[大神sku算法链接]juejin.cn/post/684490…