笔试题

82 阅读2分钟
  • 字符串中出现最多的字符以及次数
const input = "aabbccc";

const findMaxStr = (str) => {
  const map = [...str].reduce((pre, cur) => {
    if (!pre[cur]) {
      pre[cur] = 1;
    } else {
      pre[cur]++;
    }
    return pre;
  }, {});
  const [[chart, count]] = Object.entries(map).sort(
    ([, val1], [, val2]) => val2 - val1
  );
  return { chart, count };
};

console.log(findMaxStr(input));// {chart: 'c', count: 3}

  • 大数相加
  const addStrings = (num1, num2) => {
  let i = num1.length - 1;
  let j = num2.length - 1;
  let add = 0;
  const answer = [];
  while (i >= 0 || j >= 0 || add !== 0) {
    const val1 = i >= 0 ? Number(num1[i]) : 0;
    const val2 = j >= 0 ? Number(num2[j]) : 0;
    const result = val1 + val2 + add;
    answer.push(result % 10);
    add = Math.floor(result / 10);
    i -= 1;
    j -= 1;
  }
  return answer.reverse().join("")
}

const log = console.log;

log(addStrings("123456789", "98765432156464645465")); // 98765432156588100000
  • 并发限制 Scheduler
    • 类实现
class Scheduler {
  constructor(max) {
    this.max = max;
    this.count = 0; // 执行中的请求数
    this.queue = [];
  }

  async add(promiseCreate) {
    if (this.count >= this.max) {
      await new Promise((resolve) => this.queue.push(resolve));
    }
    this.count++;
    await promiseCreate();
    this.count--;
    if (this.queue.length > 0) {
      this.queue.shift()();
    }
  }
}

const delay = (time) =>
  new Promise((resolve) =>
    setTimeout(() => {
      console.log(time);
      resolve();
    }, time)
  );

const scheduler = new Scheduler(2);
scheduler.add(() => delay(1000));
scheduler.add(() => delay(500));
scheduler.add(() => delay(300));
scheduler.add(() => delay(400)); // 500 300 1000 400
  • 函数实现

利用协程的概念:

  1. 4次调用myLimit 或者接受promises 在内部循环4次来调用均可
  2. 因为是同步调用,所以会执行4次返回的函数, 让前两次的函数继续执行,多余的先阻断(await),并且把释放的方式(resolve),放在一个全局状态(queue)里, 以便其他函数可以访问
  3. 前两次函数因为没有阻断, 所以会一直走到 await request();, 当走完了,就从queue中取出一个resolve来释放
const createLimit = (max) => {
const queue = [];
let activeCount = 0;
return async (request) => {
  if (activeCount >= max) {
  // 阻断后面的函数,并且在未来释放时,继续下一行代码开始执行
    await new Promise((resolve) => queue.push(resolve));
  }
  activeCount++;
  await request();
  activeCount--;// 不减也行, 因为只需要知道阻断2之后即可
  if (queue.length) {
    queue.shift()();
  }
};
};

const myLimit = createLimit(2);
myLimit(() => delay(1000));
myLimit(() => delay(500));
myLimit(() => delay(300));
myLimit(() => delay(400));
  • 并发限制: 手动触发
class TaskPool {
  constructor(max, callback) {
    this.queue = [];
    this.max = max;
    this.callback = callback;
    this.index = 0;
    this.allLength = 0;
  }
  add(fn) {
    this.queue.push(fn);
    this.allLength = this.queue.length;
  }
  run() {
    while (this.max && this.queue.length > 0) {
      this.max--;

      const idx = this.index;
      this.index++;
      this.queue
        .shift()()
        .then(() => {
          this.max++;
          if (idx === this.allLength - 1) {
            this.callback();
          } else {
            this.run();
          }
          //   this.run();
        });
    }
  }
}

const delay = (time) =>
  new Promise((resolve) =>
    setTimeout(() => {
      console.log(time);
      resolve();
    }, time)
  );

const taskPool = new TaskPool(2, () => console.log("success"));

taskPool.add(() => delay(1000));
taskPool.add(() => delay(500));
taskPool.add(() => delay(300));
taskPool.add(() => delay(400));
taskPool.run();
// 500 300 1000 400

const obj = {
    a: {
      b: 1,
      c: 2,
      d: {
        e: 5,
      },
    },
    b: [1, 3, { a: 2, b: 3 }],
    c: 3,
  };
  
  // 返回值
  // {
  //    'a.b': 1,
  //    'a.c': 2,
  //    'a.d.e': 5,
  //    'b[0]': 1,
  //    'b[1]': 3,
  //    'b[2].a': 2,
  //    'b[2].b': 3
  //    'c': 3
  // }
  
  const flatten = (input) => {
    const output = {};

    const fn = (child, parentPath) => {
      if (Array.isArray(child)) {
        child.forEach((item, index) => {
          const fullPath = parentPath
            ? `${parentPath}[${index}]`
            : `[${index}]`;
          fn(item, fullPath);
        });
      } else if (child && typeof child === "object") {
        Object.entries(child).forEach(([k, v]) => {
          const fullPath = parentPath ? `${parentPath}.${k}` : k;
          fn(v, fullPath);
        });
      } else {
        output[parentPath] = child;
      }
    };

    fn(input, "");

    return output;
  };
  
  console.log(flatten(obj));