В июне я прошел письменный контрольный вопрос 1 большой фабрики (резюме личного опыта).

внешний интерфейс алгоритм опрос
В июне я прошел письменный контрольный вопрос 1 большой фабрики (резюме личного опыта).

Эта статья участвовала в приказе о созыве Haowen, нажмите, чтобы просмотреть:Двойные заявки на внутреннюю и внешнюю стороны, призовой фонд в 20 000 юаней ждет вас, чтобы бросить вызов!

предисловие

Фу. . Если вы не будете писать статьи, вы не сможете подняться. Но в последнее время нет ни галантерейных товаров, ни вдохновения для творчества. Итак, сегодня давайте поделимся письменными тестовыми вопросами крупных производителей.

Потому что это будет немного неожиданно, так что просто взгляните на него невзначай!Это обмен и анализ письменных тестовых вопросов Дачанга с июня по настоящее время.Я надеюсь, что детская обувь, проходящая мимо, не поскупится на ваши ручонки и поставить лайк. 😭😭😭😭

Али серии

Q1: 请实现一个 find 函数,功能等同于 document.getElementById 。

Разобрать:Сложность заключается в том, как получить узел входа. Если вы знаете входной узел, такой как корневой узел, тогда подойдет рекурсия.

Пункт осмотра:Потому что большая часть детской обуви для фронтенда обычно использует либо React, либо Vue.Мало кто знаком с некоторыми нативными манипуляциями DOM.

// 方法1,手动写递归。
const nodes = document.body; // 万物起点,获取 body DOM

function getId(node,nodeIdMap){
    if(node){ 
        if(node.id) nodeIdMap[node.id] = node; // 如果 id 属性存在,则把该DOM存入 Map
        const children = node.children;
        for(let i = 0 ; i < children.length; i++){ // 循环
            getId(children[i],nodeIdMap) // + 递归
        }
    }
    return nodeIdMap
}

const ids = getId(nodes,{})

const findId = (id) => ids[id]
// 大家可以拿这段代码试一下。
// 方法2, 借助 document.createNodeIterator 可以去MDN上查看该API
const f =  (id)=> document.createNodeIterator(
    document.body,
    NodeFilter.SHOW_ALL,
    {
      acceptNode(node) {
        return node.id === id? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
      }
    }
);

f('anyId').nextNode(); // 即可获取 任意ID 的DOM

Q2: 实现 一个 find 。

Данные теста:

var data = [
    {title: 't1', userId: '10086', name: 'Jay'},
    {title: 't2', userId: '10087', name: 'Tom1'},
    {title: 't3', userId: '10088', name: 'Tina2'},
]

Надеюсь позвонить так:

find(data).where({
name: /\d$/,
}).orderBy('userId','desc');

Результат:

[
    {title: 't3', userId: '10088', name: 'Tina2'},
    {title: 't2', userId: '10087', name: 'Tom1'}
]

Пункт осмотра:На самом деле это оператор sql. подобноselect title, userId,name from 表名 where 条件 order by userId desc

анализировать:Почему это похоже на цепной вызов? Но это яма, интервьюер точно не хочет, чтобы вы писали цепочку вызовов. (Потому что это то, что я сделал, и меня выгнали.)

// 先写个类

class FindData {

  constructor(data) {
    this.data = data;
  }

  where(regs) {
    const keys = Object.keys(regs);
    const d = this.data.filter((item) => {
      let r = true;
      for (let i = 0; i < keys.length; i++) {
        const current = item[keys[i]];
        if (!(current && regs[keys[i]].test(current))) {
          r = false;
        }
      }
      return r;
    })
    return new FindData(d);
  }

  orderBy(name, sort) {
    let fn;
    if(sort === 'desc'){
      fn = (a,b)=> b[name] - a[name]
    }else if(sort === 'asc'){
      fn = (a,b)=> a[name] - b[name]
    }
    return this.data.sort(fn)
  }
}

var find = (d) =>  new FindData(d);

find(data).where({name: /\d$/}).orderBy('userId','desc');

Q3: 将字符串转成千分位。例如 '12345678' 转化成千分位是 '12,345,678'.

Пункт осмотра:Обычный. Если то, что вы пишете, не является регулярным, это определенно позволит вам писать регулярно.零宽断言了解一下

// 零宽断言
str.replace(/\d{1,3}(?=(\d{3})+$)/g,function(s){
    return s + ','
}) 

Резюме

Письменные тестовые вопросы Али не сложны. Серьезно, это не так сложно. Но нужен очень глубокий фундамент. Часто вы не знакомы с тестом, вы не знаете, редко используется, расплывчато будет проверять вас. Во всяком случае, я преклоняю колени перед обычным утверждением нулевой ширины. 😭😭😭😭

серия байтов

Q1: 实现数组扁平化 flat 方法。

var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];

function flattenDeep(arr1) {
   return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
}
flattenDeep(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

Q2: 实现对象扁平化 flat 方法。

function flat(obj, key = "", res = {}, isArray = false) {
  for (let [k, v] of Object.entries(obj)) {
    if (Array.isArray(v)) {
      let tmp = isArray ? key + "[" + k + "]" : key + k;
      flat(v, tmp, res, true)
    } else if (typeof v === "object") {
      let tmp = isArray ? key + "[" + k + "]." : key + k + ".";
      flat(v, tmp, res)
    } else {
      let tmp = isArray ? key + "[" + k + "]" : key + k;
      res[tmp] = v
    }
  }
  return res
}

Q3: 实现 applyMiddleWare, 达到如下示例

function rawMethod(a){
    return a + 1;
}

function middleware1(next){
    return function(a){
        return next(a) + 1;
    }
}
function middleware2(next){
    return function(a){
        return next(a) + 1;
    }
}

function middleware3(next){
    return function(a){
        return next(a) + 1;
    }
}

var newMethod = applyMiddleWare(rawMethod, middleware3, middleware2);
var x = newMethod(1); 
// 要求调用顺序: middleware2 -> middleware3 -> middleware. 结果 x = 3
var newMethod2 = applyMiddleWare(newMethod, middleware1);
var y = newMethod2(10); 
// 要求调用顺序: middleware1 -> middleware2 -> middleware3 -> middleware. 结果 y = 13

Пункт осмотра:Как видно из названия, для этого требуется вручную написать метод Redux applyMiddleWare! Для чего этот метод? Хороший способ объединить вызовы подключаемых модулей промежуточного слоя. .

Анализ: требуется метод compose.

function compose(...funcs) {
    if (funcs.length === 0) {
        return args => args; //如果没有要组合的函数,则返回的函数原封不动的返回参数
    } else if (funcs.length === 1) {
        //要组合的函数只有一个
        return funcs[0];
    }
 
    // redux官方写法,在下面附有步骤分析,非常巧妙
    // return funcs.reduce((a, b) => (...args) => a(b(...args)));
 
    // 这是可读性好一些的写法,和上面代码功能一样
    return function (...args) {
        let lastReturn = null; // 记录上一个函数返回的值
        for (let i = funcs.length - 1; i >= 0; i--) {
            const func = funcs[i];
            if (i === funcs.length - 1) {
                lastReturn = func(...args);
            } else {
                lastReturn = func(lastReturn);
            }
        }
        return lastReturn;
    }
 

export function applyMiddleware(...middlewares) {
    // 接收creatStore方法
    return function (createStore) {
        // 接收reducer和默认状态 ,用于创建仓库
        return function (reducer, defaultState) {
            //创建仓库
            const store = createStore(reducer, defaultState);
            let dispatch = () => { throw new Error("目前还不能使用dispatch") };
 
            const simpleStore = {
                getState: store.getState,
                // 这里不能写成dispatch: dispatch,否则一直是上面那个报错的dispatch
                // 也不能写成store.dispatch,否则一直是最原始的dispatch
                // 写成函数形式是为了保证引用地址一致
                dispatch: (...args) => dispatch(...args)
            }
            
            //给dispatch赋值
            //根据中间件数组,得到一个dispatch创建函数的数组
            const dispatchProducers = middlewares.map(mid => mid(simpleStore));
            // 在完成dispatch前,是调用不了simpleStore中的dispatch的,只有等包装完
            dispatch = compose(...dispatchProducers)(store.dispatch)
            return {
                ...store,
                dispatch,
            }
        }
    }

、、

Q4 : 现有一台阶,共m 层。 一只青蛙每次可以跳任意层数(1 - n)的台阶,。 请问青蛙跳到第m层台阶有多种跳法?

Контрольная точка: классическая задача о прыгающих шагах лягушки. Также есть оригинальное название на кнопке Force. Эта извращенная версия прыгающих шагов лягушки также имеет оригинальное название. Я не буду писать это здесь, потому что, если вы знаете ответ, он может показаться вам немного оскорбительным для вашего IQ 😂😂😂😂

Резюме

Стиль письменных тестовых вопросов о байтах также очевиден, и мне нравится тестировать реализацию общих API. Алгоритмические вопросы, вы также можете найти похожие вопросы от Likou. Если Али — основа для проверки вашего извращения, то Байт — мозговой нерв для проверки вашего извращения.

Серия Тенсент

Q1: 写一个双链表循环树。

Я опустился на колени. Встаньте на колени. Спросите совета. (Однажды меня спросили, как написать круговое дерево односвязного списка, и теперь я обновил его до кругового дерева двусвязного списка. 😭😭😭😭😭😭😭)

Q2:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组[3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为 1。

Объект исследования: Бинарный поиск.Анализ оригинального названия

устала. Не могу больше писать. . Просто подытожу

Резюме

Письменные тестовые вопросы Tencent немного похожи на Bytes, но Tencent больше склоняется кструктура данныха такжеАлгоритмическое мышление. Это требует от вас глубокого понимания работы некоторых общих структур данных, таких как связанные списки.

(На самом деле, это относительно просто. Разбор сложных вопросов слишком кропотлив, а еще сложнее сформировать содержание статьи. Напоследок ставьте лайк, хочу обновиться 😭😭😭😭)