基础编程题汇总(二)&& 10个常见经典面试题

前言

哈喽啊兄弟们,经历了这么久的面试沉淀,我吧目前面试遇到的经典考题进行了一波总结,希望可以对同在路上的伙伴们一些帮助。都是很简单的面试题,我就直接给出答案了。

快速排序

    const arr = [5, 2, 7, 8, 34, 7, 39, 12, 56, 9, 1];
    // 期望效果
    // [1, 2, 5, 7, 7, 8, 9, 12, 34, 39, 56];

思路: 递归。

function quickSort(arr) {
  // 如果个数小于2,直接返回。
  if (arr.length <= 2) return arr;
  // 获取中间的数字
  const midIndex = Math.floor(arr.length / 2);
  const midNum = arr.splice(midIndex, 1)[0];
  const leftArr = [],
    rightArr = [];
    //  进行比较,比中间的数字小则加入leftArr,反之加入rightArr。
  for (let i = 0; i < arr.length; i++) {
    const item = arr[i];
    if (item < midNum) {
      leftArr.push(item);
    } else {
      rightArr.push(item);
    }
  }
  // 递归调用直到顺序完全正确。将他们拼合在一起。
  return quickSort(leftArr).concat(midNum, quickSort(rightArr));
}

二分查找

const nums = [1,2,3,4,5,6,7,8,9];
console.log(search(nums, 4));
// 期望结果: 3

思路: 猜数字游戏,猜中间数来最大程度的缩小范围,以便更快的找到数字。

function search(nums, target) {
  let left = 0,
    right = nums.length;
  while (left <= right) {
    const mid = Math.floor((left + right) / 2);
    console.log(mid,nums[mid]);
    if (target > nums[mid]) {
      left = mid + 1;
    } else if (target < nums[mid]) {
      right = mid - 1;
    } else {
      return mid;
    }
  }
}

柯里化

var add = function (num1, num2) {
  return num1 + num2;
};
var sum = curry(add);
console.log(sum(4)(3)(2)(1)(5)());
// 15

思路:

var add = function (num1, num2) {
  return num1 + num2;
};
function curry(add) {
  var arr = [];
  return function reply() {
    var arg = Array.prototype.slice.call(arguments);
    arr = arr.concat(arg);
    console.log('arg',arg,arr);
    if (arg.length === 0) {
      return arr.reduce(function (p, c) {
        return (p = add(p, c));
      }, 0);
    } else {
      return reply;
    }
  };
}

var sum = curry(add);
console.log(sum(4)(3)(2)(1)(5)());

扁平化

let obj = {
  a: {
    b: "a-b",
  },
  c: "ccc",
  d: {
    e: {
      f: "fff",
    },
  },
};

console.log(flat(obj));
// { 'a.b': 'a-b', c: 'ccc', 'd.e.f': 'fff' }

思路:

function flat(obj, tar = {}, keyName) {
  let _keyName = keyName ? keyName : "";
  for (let k in obj) {
    let name = _keyName ? _keyName + "." + k : k;
    if (typeof obj[k] === "object") {
      flat(obj[k], tar, name);
    } else {
      tar[name] = obj[k];
    }
  }
  return tar;
}

LazyMan

let X = LazyMan("xicongbo");
X.eat("早餐").sleep(6).eat('晚餐');
// xicongbo
// 早餐
// 等待6s之后
// 晚餐

思路:

class LazyManClass {
  constructor(name) {
    this.name = name;
    this.tasks = [];
    setTimeout(() => {
      console.log(name);
      this.next();
    });
  }

  next() {
    let fn = this.tasks.shift();
    fn && fn();
  }

  eat(food) {
    let task = () => {
      setTimeout(() => {
        console.log(food);
        this.next();
      });
    };
    this.tasks.push(task);
    return this;
  }

  sleep(time) {
    let task = () => {
      setTimeout(() => {
        console.log(time);
        this.next();
      }, time * 1000);
    };
    this.tasks.push(task);
    return this;
  }
}

function LazyMan(name) {
  return new LazyManClass(name);
}

EventBus

const eventBus = new EventBus();

// 订阅事件eventX
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模块A", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模块B", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
  console.log("模块C", obj, num);
});

// 发布事件eventX
eventBus.publish("eventX", { msg: "EventX published!" }, 1);
//模块A { msg: 'EventX published!' } 1
//模块B { msg: 'EventX published!' } 1
//模块C { msg: 'EventX published!' } 1

思路:

class EventBus {
  constructor() {
    this.eventObj = {};
    this.eventId = 0;
  }

  publish(eventName, ...args) {
    let callbackList = this.eventObj[eventName];
    for (let id in callbackList) {
      callbackList[id](...args);
    }
  }

  subscribe(eventName, callback) {
    if (!this.eventObj[eventName]) {
      this.eventObj[eventName] = {};
    }

    let id = this.eventId++
    this.eventObj[eventName][id] = callback;
    const unSubscribe = function () {
      delete this.eventObj[eventName][id];
    };
    return {unSubscribe};
  }
}

const eventBus = new EventBus();

节流和防抖(简易版本)

function debounce(fn, delay) {
  let timeOut = null;
  return function () {
    if (timeOut) clearTimeout(timeOut);
    timeOut = setTimeout(() => {
      fn.apply(this, arguments);
    }, delay);
  };
}

function throttle(fn, delay) {
  let flag = true;
  return function () {
    if (!flag) return;
    flag = false;
    setTimeout(() => {
      fn.apply(this, arguments);
      flag = true;
    }, delay);
  };
}

cloneDeep

function cloneDeep(obj) {
  let newObj = {};
  for (let k in obj) {
    let tempData = typeof obj[k] === "object" ? flat(obj[k]) : obj[k];
    newObj[k] = tempData;
  }
  return newObj;
}

括号匹配问题

console.log(isVaild('()()(){{[[]]}}'));
// true
console.log(isVaild('()()(}}}'));
// false

思路:

const isVaild = (s) => {
  let leftToRight = {
    "(": ")",
    "[": "]",
    "{": "}",
  };

  let stack = [];
  for (let i = 0; i < s.length; i++) {
    let c = s[i];
    if (leftToRight[c]) {
      stack.push(c);
    } else if (!c.length || leftToRight[stack.pop()] !== c) {
      return false;
    }
  }
  return !stack.length;
};

简易版计算器

console.log(calculate("1+3*4/2-5"));
// 2

思路: 栈,本题偏难,主要思路为,将乘除法的结果直接运算出来并推入栈中,最后统一进行加法。

function calculate(s) {
  let sign = "+",
    n = 0,
    c,
    stack = [];
  for (let i = 0; i < s.length; i++) {
    c = s.charAt(i);
    if (c <= 9 && c >= 0) {
      n = n * 10 + parseInt(c);
      if (i < s.length - 1) continue;
    }
    if (sign == "+") {
      stack.push(n);
    } else if (sign == "-") {
      stack.push(-n);
    } else if (sign == "*") {
      stack.push(stack.pop() * n);
    } else if (sign == "/") {
      stack.push(Math.trunc(stack.pop() / n));
    }
    sign = c;
    n = 0;
  }
  let res = stack.reduce((a, b) => a + b, 0);
  return res;
}