百度 手撕 面经

140 阅读3分钟

百度 手撕 面经

二叉树最远节点的距离(二叉树的直径)

function TreeNode(val) {
    this.val = val;
    this.left = this.right = null;
}
​
var diameterOfBinaryTree = function(root) {
    let maxDiameter = 0;
​
    function dfs(node) {
        if (!node) return 0;
        let leftDepth = dfs(node.left);
        let rightDepth = dfs(node.right);
        
        // 更新最大直径
        maxDiameter = Math.max(maxDiameter, leftDepth + rightDepth);
​
        // 返回节点的最大深度
        return 1 + Math.max(leftDepth, rightDepth);
    }
​
    dfs(root);
    return maxDiameter;
};
​
// 示例
let root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);
​
console.log(diameterOfBinaryTree(root)); // 输出应为 3 (节点4 -> 2 -> 5的路径)

统计出现两次的元素

function findDuplicates(arr) {
    let count = {}
    let newArr = []
    arr.forEach(item=>{
        // count[item] = (count[item]||0)+1
        if(count[item]){
            count[item]++
        }else{
            count[item] = 1
        }
    })
    for(let item in count){
        if(count[item] === 2){
            newArr.push(parseInt(item))
        }
    }
    return newArr
}
​
// 示例用法
console.log(findDuplicates([1, 2, 2, 3, 4, 5, 5, 6]));  // 输出: [2, 5]

手撕解析URL参数

function parseUrlParams(url) {
  const queryString = url.split('?')[1];
  const params = queryString.split('&');
  const result = {};
​
  params.forEach(param => {
    const [key, value] = param.split('=');
    result[key] = decodeURIComponent(value);
  });
​
  return result;
}
​
// 示例用法
console.log(parseUrlParams('http://example.com?page=3&limit=10&query=hello%20world'));
// 输出: { page: '3', limit: '10', query: 'hello world' }

合并区间

function mergeIntervals(intervals) {
    if (!intervals.length) return intervals;
    intervals.sort((a, b) => a[0] - b[0]);
    const result = [intervals[0]];
​
    for (let i = 1; i < intervals.length; i++) {
        const prev = result[result.length - 1];
        const current = intervals[i];
        if (current[0] <= prev[1]) {
            prev[1] = Math.max(prev[1], current[1]);
        } else {
            result.push(current);
        }
    }
​
    return result;
}
​
// 使用示例
console.log(mergeIntervals([[1, 3], [2, 6], [8, 10], [15, 18]]));
// 输出: [[1, 6], [8, 10], [15, 18]]

反转字符串

function reverseString(str) {
  return str.split('').reverse().join('');
}
​
console.log(reverseString('hello')); // 'ollelo'

全排列

function permute(arr) {
  const result = [];
​
  function backtrack(path, options) {
    if (path.length === arr.length) {
      result.push([...path]);
      return;
    }
​
    for (let i = 0; i < options.length; i++) {
      path.push(options[i]);
      backtrack(path, options.slice(0, i).concat(options.slice(i + 1)));
      path.pop();
    }
  }
​
  backtrack([], arr);
  return result;
}
​
console.log(permute([1, 2, 3]));

手写Promise

class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
​
    const resolve = value => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };
​
    const reject = reason => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };
​
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
​
  then(onFulfilled, onRejected) {
    if (this.state === 'fulfilled') {
      onFulfilled(this.value);
    }
    if (this.state === 'rejected') {
      onRejected(this.reason);
    }
    if (this.state === 'pending') {
      this.onFulfilledCallbacks.push(() => onFulfilled(this.value));
      this.onRejectedCallbacks.push(() => onRejected(this.reason));
    }
  }
}
​
// 使用
const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('Success!');
  }, 1000);
});
​
promise.then(value => {
  console.log(value); // 'Success!'
}, reason => {
  console.error(reason);
});

fetch-promise

function myFetchWithTimeout(url, options, timeout = 5000) {
  // 创建 fetch 请求的 Promise
  const fetchPromise = new Promise((resolve, reject) => {
    fetch(url, options)
      .then(response => {
        if (response.ok) {
          resolve(response);
        } else {
          reject(new Error('Fetch error: ' + response.statusText));
        }
      })
      .catch(error => reject(new Error('Network error: ' + error.message)));
  });
​
  // 创建超时的 Promise
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => reject(new Error('Fetch timeout')), timeout);
  });
​
  // 使用 Promise.race 执行两个 Promise
  return Promise.race([fetchPromise, timeoutPromise]);
}
​
// 使用示例
myFetchWithTimeout('https://jsonplaceholder.typicode.com/todos/1', {}, 3000)
  .then(response => response.json())
  .then(data => console.log('Fetch success:', data))
  .catch(error => console.error('Fetch error:', error));
​

数组去重

//使用 Set
const uniqueArray = arr => [...new Set(arr)];
console.log(uniqueArray([1, 2, 2, 3])); // [1, 2, 3]//使用 filter 和 indexOf
const uniqueArray = arr => arr.filter((item, index) => arr.indexOf(item) === index);
console.log(uniqueArray([1, 2, 2, 3])); // [1, 2, 3]//使用 reduce
const uniqueArray = arr => arr.reduce((acc, item) => {
  if (!acc.includes(item)) acc.push(item);
  return acc;
}, []);
console.log(uniqueArray([1, 2, 2, 3])); // [1, 2, 3]

函数柯里化

将一个多参数函数转换为一系列单参数函数的过程

function curry(fn) {
  const arity = fn.length;
  return function curried(...args) {
    if (args.length >= arity) {
      return fn(...args);
    } else {
      return function(...nextArgs) {
        return curried(...args, ...nextArgs);
      };
    }
  };
}
​
// 使用示例
function add(a, b, c) {
  return a + b + c;
}
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 6

实现 add(1, 2, 3) === add(1)(2)(3)

function add(a) {
  return function(b) {
    return function(c) {
      return a + b + c;
    };
  };
}
​
console.log(add(1, 2, 3) === add(1)(2)(3)); // true

手写 new

new 操作符执行以下步骤:

  1. 创建一个新对象。
  2. 将构造函数的 prototype 赋值给新对象的 __proto__
  3. 执行构造函数,将 this 绑定到新对象。
  4. 如果构造函数返回一个对象,则返回该对象,否则返回新对象。
function myNew(constructor, ...args) {
  const obj = {};
  Object.setPrototypeOf(obj, constructor.prototype);
  const result = constructor.apply(obj, args);
  return result !== null && (typeof result === 'object' || typeof result === 'function') ? result : obj;
}
​
// 使用示例
function Person(name) {
  this.name = name;
}
​
const person = myNew(Person, 'John');
console.log(person.name); // John

二叉树前序遍历

function preOrderTraversal(root) {
  const result = [];
  function traverse(node) {
    if (!node) return;
    result.push(node.value);
    traverse(node.left);
    traverse(node.right);
  }
  traverse(root);
  return result;
}