2020年冬季前端筆試題總結

趁你還年輕 發表於 2020-12-30

image.png

原文地址:一些特別棒的面試題[4]

最近面試了一些公司,拿了一些offer,不記錄概念題目,僅記錄coding類題目。
小夥伴們空閒時間可以做這些題目練練手。

  • 只出現一次的數字
  • 彙總區間
  • 實現紅綠燈效果
  • 陣列去重
  • 返回 excel 表格列名
  • 檢測空物件
  • 實現a+a+a列印'abc'
  • 實現一個Event模組
  • 大整數相加
  • SuperPerson繼承Person
  • 字串隱藏部分內容

只出現一次的數字

給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
示例 1:

輸入: [2,2,1]
輸出: 1
示例 2:

輸入: [4,1,2,1,2]
輸出: 4
這是一道leetcode 簡單難度的題。
題目:leetcode 136 只出現一次的數字
題解:136 只出現一次的數字

/**
 * @param {number[]} nums
 * @return {number}
 */
var singleNumber = function (nums) {
  /** 解法1:暴力遍歷
   *  效能:704ms 40.5MB
   */
  let numsSet = Array.from(new Set(nums));
  let numsMap = numsSet.map((num) => ({
    num,
    count: 0,
  }));
  nums.forEach((num, i) => {
    numsMap.forEach((numM, j) => {
      if (numM.num === num) {
        numM.count++;
      }
    });
  });
  let filterArr = numsMap.filter((num) => num.count === 1);
  return filterArr[0].num;
  /** 解法2:Set 首次出現add 二次出現delete
   *  效能: 72 ms 38MB
   */
  let numsSet = new Set();
  for (let i = 0; i < nums.length; i++) {
    if (!numsSet.has(nums[i])) {
      numsSet.add(nums[i]);
    } else {
      numsSet.delete(nums[i]);
    }
  }
  return [...numsSet][0];
};

彙總區間

給定一個亂序整形陣列[0,1,7,13,15,16,2,4,5],找出其中連續出現的數字區間為如下:["0->2", "4->5", "7", "13", "15->16"]
這是一道leetcode 中等難度的題。
題目:leetcode 228 彙總區間
題解:228彙總區間(Summary Ranges)

function continuous(arr) {
  arr.sort((a, b) => a - b);
  let stack = [];
  let result = [];
  for (let i = 0; i < arr.length; i++) {
    if (stack.length === 0 || arr[i] - stack[stack.length - 1] === 1) {
      stack.push(arr[i]);
    } else {
      if (stack.length > 1) {
        result.push(`${stack[0]}->${stack[stack.length - 1]}`);
      } else {
        result.push(`${stack[0]}`);
      }

      stack = [];
      stack.push(arr[i]);
    }
    if (i === arr.length - 1) {
      if (stack.length > 1) {
        result.push(`${stack[0]}->${stack[stack.length - 1]}`);
      } else {
        result.push(`${stack[0]}`);
      }
    }
  }
  return result;
}
console.log(continuous([0, 1, 7, 13, 15, 16, 2, 4, 5]));

實現紅綠燈效果,使用console 輸出 “紅”、“綠”、“黃”示意,等待時間分別為 3s、2s、1s

function trafficCtrl() {
  // timeline 紅0~2 綠3~4 黃5
  const borders = { red: 3, green: 5, yellow: 6 };
  let current = 0;
  setInterval(() => {
    if (current >= 0 && current <= 2) {
      console.log('紅', borders.red - current);
    } else if (current >= 3 && current <= 4) {
      console.log('綠', borders.green - current);
    } else {
      console.log('黃', borders.yellow - current);
    }
    current++;
    if (current > 5) {
      current = 0;
    }
  }, 1000);
}

trafficCtrl();

紅 3
紅 2
紅 1
綠 2
綠 1
黃 1
紅 3
紅 2

陣列去重

輸入:
['1', '2', '3', 1, '2', undefined, undefined, null, null, 1, 'a','b','b'];
輸出:
["1", "2", "3", 1, undefined, null, "a", "b"]

// 解法1:includes
function removeDuplicate(arr) {
    const result = [];
    for(const item of arr){
       if(!result.includes(item)) result.push(item);
    }
    return result;
}
// 解法2:Map
function removeDuplicate(arr) {
     const map = new Map();
    for(const item of arr){
       if(!map.has(item)) map.set(item, true);
      }
     const result = [...map.keys()];
    return result;
}
// 解法3:對撞指標
function removeDuplicate(arr) {
     const map = new Map();
     let i = 0;
     let j = arr.length - 1;
     while(i<=j){
            if(!map.has(arr[i])) map.set(arr[i], true);
            if(!map.has(arr[j])) map.set(arr[j], true);
            i++;
            j--;
     }
     const result = [...map.keys()];
          return result;
}
// 解法4:filter
function removeDuplicate(arr) {
    return arr.filter((item, i)=> arr.indexOf(item) === i)
}

寫一個函式返回 excel 表格列名

輸入:1 輸出:A
輸入:2 輸出:B
輸入:26 輸出:Z
輸入:27 輸出:AA
輸入:52 輸出:AZ

這是一道leetcode 簡單難度的題。
題目:leetcode 168 Excel表列名稱
題解:168 Excel表列名稱

function getExcelColumn(column) {
    const obj = {};
    let i = 0;
    const startCode = "A".charCodeAt();
    while (i < 26) {
        obj[i + 1] = String.fromCharCode(startCode + i);
        i++;
    }
    if (column <= 26) {
        return obj[column]
    }
    const stack = [];
    const left = column % 26;
    const floor = Math.floor(column / 26);

    if (left) {
        stack.unshift(obj[left])
        stack.unshift(obj[floor]);
    } else {
        stack.unshift('Z')
        stack.unshift(obj[floor - 1]);
    }
    const result = stack.join("");
    return result;
}

如何檢測一個空物件

// 解法1: Object.prototype.toString.call和JSON.stringify
function isObjEmpty(obj){
    return Object.prototype.toString.call(obj)==="[Object object]" && JSON.stringify({}) === "{}";
}
// 解法2: Object.keys() Object.values()
function isObjEmpty(obj){
    return Object.keys(obj).length === 0 || Object.values(obj).length === 0;
}
// 解法3:for...in
function isObjEmpty(obj){
    for(key in obj){
        if(key) return false
    }
    return true;
}

實現a+a+a列印'abc'

console.log(a + a + a); // 列印'abc'

// 題目一
/*
  console.log(a + a + a); // 列印'abc'
*/

/**
 * 解法1: Object.defineProperty() 外部變數
 */
let value = "a";
Object.defineProperty(this, "a", {
  get() {
    let result = value;
    if (value === "a") {
      value = "b";
    } else if (value === "b") {
      value = "c";
    }
    return result;
  },
});
console.log(a + a + a);
/**
 * 解法1(優化版):Object.defineProperty() 內部變數
 */
Object.defineProperty(this, "a", {
  get() {
    this._v = this._v || "a";
    if (this._v === "a") {
      this._v = "b";
      return "a";
    } else if (this._v === "b") {
      this._v = "c";
      return "b";
    } else {
      return this._v;
    }
  },
});
console.log(a + a + a);

/**
 * 解法2: Object.prototpye.valueOf()
 */
let index = 0;
let a = {
  value: "a",
  valueOf() {
    return ["a", "b", "c"][index++];
  },
};
console.log(a + a + a);

/**
 * 解法3:charCodeAt,charFromCode
 */
let code = "a".charCodeAt(0);
let count = 0;
Object.defineProperty(this, "a", {
  get() {
    let char = String.fromCharCode(code + count);
    count++;
    return char;
  },
});
console.log(a + a + a); // 'abc'

/**
 * 解法3(優化版一):內部變數this._count和_code
 */
Object.defineProperty(this, "a", {
  get() {
    let _code = "a".charCodeAt(0);
    this._count = this._count || 0;
    let char = String.fromCharCode(_code + this._count);
    this._count++;
    return char;
  },
});
console.log(a + a + a); // 'abc'

/**
 * 解法3(優化版二):內部變數this._code
 */
Object.defineProperty(this, "a", {
  get() {
    this._code = this._code || "a".charCodeAt(0);
    let char = String.fromCharCode(this._code);
    this._code++;
    return char;
  },
});
console.log(a + a + a); // 'abc'

/*
 題目擴充套件: 列印`a...z`
 a+a+a; //'abc'
 a+a+a+a; //'abcd'
*/
/**
 * charCodeAt,charFromCode
 */
let code = "a".charCodeAt(0);
let count = 0;
Object.defineProperty(this, "a", {
  get() {
    let char = String.fromCharCode(code + count);
    if (count >= 26) {
      return "";
    }
    count++;
    return char;
  },
});
// 列印‘abc’
console.log(a + a + a); // 'abc'

// 列印‘abcd’
let code = "a".charCodeAt(0);
let count = 0;
// {...定義a...}
console.log(a + a + a); // 'abcd'

// 列印‘abcdefghijklmnopqrstuvwxyz’
let code = "a".charCodeAt(0);
let count = 0;
// {...定義a...}
let str = "";
for (let i = 0; i < 27; i++) {
  str += a;
}
console.log(str); // "abcdefghijklmnopqrstuvwxyz"

/*
 題目擴充套件(優化版): 列印`a...z`
 a+a+a; //'abc'
 a+a+a+a; //'abcd'
*/

Object.defineProperty(this, "a", {
  get() {
    this._code = this._code || "a".charCodeAt(0);
    let char = String.fromCharCode(this._code);
    if (this._code >= "a".charCodeAt(0) + 26) {
      return "";
    }
    this._code++;
    return char;
  },
});
// 列印‘abc’
console.log(a + a + a); // 'abc'

實現一個Event模組

/**
 * 說明:簡單實現一個事件訂閱機制,具有監聽on和觸發emit方法
 * 示例:
 * on(event, func){ ... }
 * emit(event, ...args){ ... }
 * once(event, func){ ... }
 * off(event, func){ ... }
 * const event = new EventEmitter();
 * event.on('someEvent', (...args) => {
 *     console.log('some_event triggered', ...args);
 * });
 * event.emit('someEvent', 'abc', '123');
 * event.once('someEvent', (...args) => {
 *     console.log('some_event triggered', ...args);
 * });
 * event.off('someEvent', callbackPointer); // callbackPointer為回撥指標,不能是匿名函式
 */

class EventEmitter {
  constructor() {
    this.listeners = [];
  }
  on(event, func) {
    const callback = () => (listener) => listener.name === event;
    const idx = this.listeners.findIndex(callback);
    if (idx === -1) {
      this.listeners.push({
        name: event,
        callbacks: [func],
      });
    } else {
      this.listeners[idx].callbacks.push(func);
    }
  }
  emit(event, ...args) {
    if (this.listeners.length === 0) return;
    const callback = () => (listener) => listener.name === event;
    const idx = this.listeners.findIndex(callback);
    this.listeners[idx].callbacks.forEach((cb) => {
      cb(...args);
    });
  }
  once(event, func) {
    const callback = () => (listener) => listener.name === event;
    let idx = this.listeners.findIndex(callback);
    if (idx === -1) {
      this.listeners.push({
        name: event,
        callbacks: [func],
      });
    }
  }
  off(event, func) {
    if (this.listeners.length === 0) return;
    const callback = () => (listener) => listener.name === event;
    let idx = this.listeners.findIndex(callback);
    if (idx !== -1) {
      let callbacks = this.listeners[idx].callbacks;
      for (let i = 0; i < callbacks.length; i++) {
        if (callbacks[i] === func) {
          callbacks.splice(i, 1);
          break;
        }
      }
    }
  }
}

// let event = new EventEmitter();
// let onceCallback = (...args) => {
//   console.log("once_event triggered", ...args);
// };
// let onceCallback1 = (...args) => {
//   console.log("once_event 1 triggered", ...args);
// };
// // once僅監聽一次
// event.once("onceEvent", onceCallback);
// event.once("onceEvent", onceCallback1);
// event.emit("onceEvent", "abc", "123");

// // off銷燬指定回撥
// let onCallback = (...args) => {
//   console.log("on_event triggered", ...args);
// };
// let onCallback1 = (...args) => {
//   console.log("on_event 1 triggered", ...args);
// };
// event.on("onEvent", onCallback);
// event.on("onEvent", onCallback1);
// event.emit("onEvent", "abc", "123");

// event.off("onEvent", onCallback);
// event.emit("onEvent", "abc", "123");

大整數相加

/**
* 請通過程式碼實現大整數(可能比Number.MAX_VALUE大)相加運算
* var bigint1 = new BigInt('1231230');
* var bigint2 = new BigInt('12323123999999999999999999999999999999999999999999999991');
* console.log(bigint1.plus(bigint2))
*/
function BigInt(value) {
  this.value = value;
}

BigInt.prototype.plus = function (bigint) {
  let aArr = this.value.split("");
  let bArr = bigint.value.split("");
  let stack = [];
  let count = 0;
  while (aArr.length !== 0 || bArr.length !== 0) {
    let aPop = aArr.pop() || 0;
    let bPop = bArr.pop() || 0;
    let stackBottom = 0;
    if (stack.length > count) {
      stackBottom = stack.shift();
    }
    let sum = parseInt(aPop) + parseInt(bPop) + parseInt(stackBottom);
    if (sum < 10) {
      stack.unshift(sum);
    } else if (sum >= 10) {
      stack.unshift(sum - 10);
      stack.unshift(1);
    }
    count++;
  }
  return stack.join("");
};

SuperPerson繼承Person

//寫一個類Person,擁有屬性age和name,擁有方法say(something)
//再寫一個類Superman,繼承Person,擁有自己的屬性power,擁有自己的方法fly(height) ES5方式

function Person(age, name){
    this.age = age;
        this.name = name;
}
Person.prototype.say = function(something) {
    // ...
}

function Superman(age, name, power){
        Person.call(this, age, name, power);
    this.power = power;
}
Superman.prototype = Object.create(Person.prototype);
Superman.prototype.constructor = Superman;

Superman.prototype.fly = function(height) {
    // ...
}

let superman = new Superman(25, 'GaoKai', 'strong');

// class方式
class Person {
  constructor(age, name){
    this.age = age;
    this.name = name;
  }
  say(something){
      // ...
      console.log("say");
  }
}
class Superman extends Person{
  constructor(age, name, power){
    super(age, name)
    this.power = power;
  }
  fly(height){
    // ...
    console.log("fly");
  }
}

let superman = new Superman(25, 'GaoKai', 'strong');

字串隱藏部分內容

/**
 * 字串隱藏部分內容
 * 說明:實現一個方法,接收一個字串和一個符號,將字串中間四位按指定符號隱藏
 *   1. 符號無指定時使用星號(*)
 *   2. 接收的字串小於或等於四位時,返回同樣長度的符號串,等同於全隱藏,如 123,隱藏後是 ***
 *   3. 字串長度是大於四位的奇數時,如 123456789,隱藏後是 12****789,奇數多出來的一位在末尾
 * 示例:
 *   mask('blibaba', '#');  // b####ba
 *   mask('05716666');   // 05****66
 *   mask('hello');  // ****o
 *   mask('abc', '?');  // ???
 *   mask('嗶裡巴巴集團', '?'); // 嗶????團
 */
function mask(str, char = "*") {
  if(str.length<=4) return char.repeat(str.length);
  /* 程式碼實現 */
  let result = "";
  let i = Math.floor(str.length / 2) - 1;
  let j = Math.floor(str.length / 2);
  while(result.length!==str.length){
    if(j - i <= 4){
          result = char + result;
        result += char ;
    } else {
        result = (str[i] || "") + result;
        result += str[j] ;
    }
    i--;
    j++;
  }
  return result;
}

期待和大家交流,共同進步,歡迎大家加入我建立的與前端開發密切相關的技術討論小組:

2020年冬季前端筆試題總結

努力成為優秀前端工程師!

相關文章