分享下最近面试做的编程题

2,159 阅读5分钟

某手和某乎、某易,这些都是技术面走完的

leetcode 常见的题目就不列出来了,有些也记不清楚了,大概列一下

1. 求 dom 树的最大深度

2. 求和函数?

A(1)() ===1
A(2)(2)() ===4
A(1)(2)(3)() ===6
// ...

3. throttle 和 debounce

4. 10进制转2进制

5. 找出页面所有的以s开头的元素,类似<script>、<span>

6. 实现 reduce

7. JSON.stringify 会导致什么问题, 检查循环引用

8. 给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串,判断字符串是否有效。

9. 实现 Promise.allSettled/Promise.all

某一面编程就挂了的(吐了

1. 实现一个Promise.race

2. XHR 请求缓存与合并

3. 将一个 html 字符串变成树的形式

4. 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

5. 给定两个二叉树,编写一个函数来检验它们是否相同。

我的解答

注意,是我的解答,就是我当时的答案

1. 求 dom 树的最大深度

const getDepth = (node) => {
    let max = 0;
    void function fn(node, depth) {
       const children = Arrary.from(node.children);
        if (!children.length) {
            max = Math.max(max, depth);
        };

        children.forEach(nd => {
            fn(nd, ++depth);
        })
    }(node, 0);

    return max;
}

2. 求和函数?

A(1)() ===1
A(2)(2)() ===4
A(1)(2)(3)() ===6
// ...
const A = (num1, sum = 0) => {
    return function(num2) {
        if (num2 !== undefined) return A(num2, sum + num1);
        return sum + num1;
    };
};

3. throttle 和 debounce

这个就不写了,网上一大堆

4. 10进制转2进制

const fn = (num) => {
    let result = '';
    void function trans(m) {
        const n = m % 2;
        result = n + result;
        const i = Math.floor(m / 2);
        if (i !== 0) trans(i);
    }(num);
    
    return result;
};

5. 找出页面所有的以s开头的元素,类似<script>、<span>

const fn = node => {
    const result = [];
    
    void function find(n) {
        const children = Array.from(n.children);
        if (children.length) {
            children.forEach(e => {
                if (/^S/.test(e.tagName)){
                    result.push(e);
                };
                find(e);
            }); 
        }
    }(node);
    
    return result;
};

6. 实现 reduce

const reduce = (arr, cb, init) => {
    let result = init;
    for (let i = 0; i < arr.length; i++) {
        result = cb(result, arr[i], i, arr);
    }
    
    return result;
};

7. JSON.stringify 会导致什么问题, 检查循环引用

const a = {};
const b = {};

a.a = b;
b.b = a;

const fn = obj => {
  const map = new WeakMap();
  const check = t => {
    if (typeof t !== 'object') {
      return true;
    }

    const keys = Object.keys(t);

    for (let i = 0, l = keys.length; i < l; i++) {
      const val = t[keys[i]];
      if (typeof val === 'object') {
        if (map.has(val)) return false;

        map.set(val);
        return check(val);
      }

      return true;
    }
  };

  return check(obj);
};
console.log(fn(a));

8. 给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串,判断字符串是否有效。

这题找不到自己写的答案了,反正就是出入栈

9. 实现 Promise.allSettled/Promise.all

大概,具体什么样看 MDN 吧。。。

const allSettled = promises => {
    let result = [];
    let count = 0;
    return new Promise((resolve, reject) => {
        promises.forEach((req, i) => {
            req
                .then(data => {
                    result[i] = { status: 'fulfilled', value: data };
                })
                .catch(err => {
                    result[i] = { status: 'rejected', err };
                })
                .finally(() => {
                    i++;
                    if (count === arr.length) resolve(result);
                })
        });.
    })
};

某一面编程就挂了的,说实话我也没想到一面会挂。。。

因为一面挂了,所以写的东西大家都只当参考吧。。。

1. 实现一个Promise.race

const race = promises => {
  return new Promise((resolve, reject) => {
    promises.forEach(req => {
      Promise.resolve(req).then(resolve).catch(reject);
    });
  });
};

2. XHR 请求缓存与合并

const getMemoizedUserInfo = resolver => {
  const cache = new Map();

  function request(...ids) {
    const key = resolver ? resolver(ids) : ids[0];

    if (cache.has(key)) {
      return Promise.resolve(cache.get(key));
    }

    const getUser = (...list) => list.length > 1 ? getUserByIds(list) : getUserById(list[0]);

    return new Promise((resolve, reject) => {
      getUser(...ids)
        .then(data => {
          cache.set(key, data);

          resolve(data);
        }, reject);
    });
  }

  return request;
};

3. 将一个 html 字符串变成树的形式

const htmlParser = html => {
  const result = { children: [] };
  const transString2array = html => {
    let privateHtml = html;
    let temporaryHtml = html;
    const tagReg = /\<[^\<\>]*?\>/;
    const sReg = /\s/g;
    const arr = [];
    while (privateHtml.match(tagReg)) {
      privateHtml = temporaryHtml.replace(tagReg, (v, i) => {
        if (i > 0) {
          const value = temporaryHtml.slice(0, i);
          if (value.replace(sReg, '').length > 0) {
            arr.push(value);
          }
        }
        temporaryHtml = temporaryHtml.slice(i + v.length);
        arr.push(v);
        return '';
      });
    }
    return arr;
  };

  const tagList = transString2array(html);
  const stack = [];
  let tpl;
  tagList.forEach(node => {
    let isTextContent = true;
    // startTag
    if (/<[^\>\/]+\/?>/.test(node)) {
      isTextContent = false;
      const tag = node.replace(/<([^\s]+)[^\>\/]*\/?>/, '$1');
      let attrObj = {};
      const selfClose = /\/>$/.test(node);
      node.replace(/<[^\s]+([^\>\/]*)>/, (_, attrStr) => {
        attrStr.replace(/(\S+)=\"([^"]+)\"/g, (_, key, value) => {
          attrObj = {...attrObj,  [key]: value};

          return '';
        });

        return '';
      });

      if (!stack.length) {
        stack.push(Object.assign(result, { tag, selfClose, text: '', attributes: attrObj, children: [] }));
      } else {
        tpl = { tag, selfClose, text: '', attributes: attrObj, children: [] };
        const footer = stack[stack.length - 1];
        footer.children.push(tpl);
        if (!selfClose) {
          stack.push(tpl);
        }
      }
    }
    // closeTag
    if (/<\/[^\>\/]+>/.test(node)) {
      isTextContent = false;
      stack.pop();
    }

    // textContent
    if (isTextContent) {
      const footer = stack[stack.length - 1];
      footer.text += node;
    }
  });

  return result;
};

可优化的地方非常非常多(tpl变量意义不明,replace完全可以用match替代等,正则也乱写),还有些bug...不过这个是我当时提交的答案,一点没改。。

console.log(htmlParser(`<html>
<head class='aaa'><title>Hello</title></head>
<body>
<div id="container"><br />
    <div class="header" title="aaa">header
    </div>
    <div class="content">content
    </div>
    <div class="footer">footer
    </div>
</div>
<table>
    <tr>
        <th style="width: 10%">版本</th>
        <th style="width: 15%">更新时间</th>
        <th style="width: 20%">贡献者</th>
        <th>编辑原因</th>
        <th style="width: 10%">操作</th>
    </tr>
</table>
</body>
</html>`))

4. 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。

注意你不能在买入股票前卖出股票。

本质上就是找最小的点

const getMaxDiff = (arr: number[]) => {
  let buy = 0;
  let sell = 0;
  let min = 0;
  let diff = 0;
  for (let i = 0; i < arr.length; i++) {
    const current = arr[i];
    if (current - arr[buy] > diff) {
      sell = i;
      diff = current - arr[buy];
    }

    if (current - arr[min] > diff) {
      buy = min;
      sell = i;
      diff = current - arr[min];
    }

    if (current < arr[min]) {
      min = i;
    }
  }

  // 因为是第几天,所以 +1
  return [buy + 1, sell + 1, diff];
};

5. 给定两个二叉树,编写一个函数来检验它们是否相同

选择了广度优先

const treeDiff = (tree1: ITreeNode, tree2: ITreeNode) => {
  const stack1 = [tree1];
  const stack2 = [tree2];
  let i = 0;
  while (i < stack1.length || i < stack2.length) {
    if (stack1[i] === null || stack2[i] === null) {
      if (stack1[i] !== stack2[i]) {
        return false;
      }
      i++;
      continue;
    }

    if (stack1[i].value !== stack2[i].value) {
      return false;
    }

    stack1.push(stack1[i].left || null);
    stack1.push(stack1[i].right || null);
    stack2.push(stack2[i].left || null);
    stack2.push(stack2[i].right || null);
    i++;
  }

  return true;
};

const tree1 = { left: { value: 3, right: { value: 3, left: { value: 2, right: { value: 12 } } } }, value: 1 };
const tree2 = { left: { value: 3, right: { value: 3, left: { value: 2, right: { value: 12 } } } }, value: 1 };
const tree3 = { left: { value: 3, right: { value: 3, left: { value: 2, right: { value: 13 } } } }, value: 1 };
console.log(treeDiff(tree1, tree2), treeDiff(tree1, tree3));

⚠️⚠️⚠️注意啊!!!我这样写,编程面是挂了的,所以只是给出我的思路,你把我这个当答案,也会挂的。。。

总结

手写题目只是考核的一方面,写好能加分,写不出来基本上离挂就不远,题目思路也没说,后面看情况补充吧,大概这样