7

趁你还年轻,做个优秀的前端工程师

 3 years ago
source link: https://segmentfault.com/a/1190000038701201
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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;
}

期待和大家交流,共同进步,欢迎大家加入我创建的与前端开发密切相关的技术讨论小组:

努力成为优秀前端工程师!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK