算法总结

44 阅读4分钟

leetCode

二叉树

二叉树的直径

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var diameterOfBinaryTree = function(root) {
    
    let maxDiameter = 0;
    const traverse = (root) => {
        if(!root) return 0 ;
        let leftMax = traverse(root.left);
        let rightMax = traverse(root.right);
        maxDiameter = Math.max(maxDiameter, leftMax + rightMax);
        return 1 + Math.max(leftMax, rightMax);
    }

    traverse(root);
    return maxDiameter
};

二叉树层序遍历

  • 解法一:使用栈
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function(root) {
    // 熟悉的做法是队列
    let res = [];

    if(!root) return res;

    let q = [];

    q.push(root);

    while(q.length > 0){
        let size = q.length;
        let sub = [];

        while(size > 0){
            let curr = q.shift();
            sub.push(curr.val);
            if(curr.left) q.push(curr.left);
            if(curr.right) q.push(curr.right);
            size--;
        }

        res.push(sub);
    }

    return res;
};
  • 解法二:使用dfs(深度优先)
/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function(root) {
    const result = [];

    const traverse = (node, depth) => {
        if(!node) return;

        if(!result[depth]){
            result[depth] = [];
        }

        result[depth].push(node.val);

        traverse(node.left, depth + 1);

        traverse(node.right, depth + 1);

    }

    traverse(root, 0);

    return result;
};

排序算法

1、冒泡排序

function bubbleSort(arr) {
  // 创建副本,避免修改原数组
  const result = [...arr];

  const n = result.length;

  for (let i = 0; i < n - 1; i++) {
    for (let j = 0; j < n - 1 - i; j++) {
      if (result[j] > result[j + 1]) {
        [result[j], result[j + 1]] = [result[j + 1], result[j]];
      }
    }
  }
  return result;
}

console.log(bubbleSort([3, 1, 6, 2, 8]));

2、快速排序

function quickSort(arr) {
  if (arr.length <= 1) return arr;

  const pivotIndex = Math.floor(arr.length / 2);
  const pivot = arr[pivotIndex];

  const left = [];
  const middle = [];
  const right = [];

  for (let i = 0; i < arr.length; i++) {
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else if (arr[i] === pivot) {
      middle.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }

  return [...quickSort(left), ...middle, ...quickSort(right)];
}turn [...quickSort(left), ...middle, ...quickSort(right)];
}

非leetcode

1、输出出现次数最多的字母的前缀数之和

function fn(str) {
  const charCount = {};

  for (let i = 0; i < str.length; i++) {
    const char = str[i].toLowerCase();
    if (!charCount[char]) {
      charCount[char] = [];
    }
    charCount[char].push(i);
  }

  // 找出出现次数最多的字母
  let maxChar = '';
  let maxCount = 0;
  for (const [char, positions] of Object.entries(charCount)) {
    if (positions.length > maxCount) {
      maxCount = positions.length;
      maxChar = char;
    }
  }

  const sum = charCount[maxChar].reduce((a, b) => a + b, 0);
  return {
    maxChar,
    sum,
  };
}
// p: 0
// a: 1
// t: 2, 8 ===> 2+8 = 10
// c: 3
// h: 4
// r: 5
// o: 6
// u: 7
// e: 9
// s: 10

console.log(fn('patchRoutes'));

2、react手写一个十分秒的倒计时

// 手写一个倒计时组件
import React, { useState, useEffect } from 'react';
function CountDown({ initialTime = 3600 }) {
  // 默认1h
  const [timeLeft, setTimeLeft] = useState(initialTime);

  // 格式化数字

  const formatTime = (seconds) => {
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const secs = seconds % 60;

    return {
      hours: hours.toString().padStart(2, '0'),
      minutes: minutes.toString().padStart(2, '0'),
      seconds: secs.toString().padStart(2, '0'),
    };
  };

  const { hours, minutes, seconds } = formatTime(timeLeft);

  useEffect(() => {
    let timer = setInterval(() => {
      setTimeLeft((prev) => {
        if (prev <= 1) {
          console.log('倒计时结束');
          return 0;
        }
        return prev - 1;
      });
    }, 1000);

    return () => clearInterval(timer);
  }, []);

  return (
    <div>
      <div>时:{hours}</div>
      <div>分:{minutes}</div>
      <div>秒:{seconds}</div>
    </div>
  );
}

export default CountDown;

3、使用js实现一个栈

class Stack {
  constructor() {
    this.items = [];
  }

  /**
   * 1. 入栈 - 将元素添加到栈顶
   * @param {*} element 要添加的元素
   */
  push(element) {
    this.items.push(element);
  }

  /**
   * 2. 出栈 - 移除并返回栈顶元素
   * @returns {*} 栈顶元素,如果栈为空返回undefined
   */
  pop() {
    if (this.isEmpty()) {
      return undefined;
    }
    return this.items.pop();
  }

  /**
   * 3. 查看栈顶元素(不移除)
   * @returns {*} 栈顶元素,如果栈为空返回undefined
   */
  peek() {
    if (this.isEmpty()) {
      return undefined;
    }
    return this.items[this.items.length - 1];
  }

  /**
   * 4. 判断栈是否为空
   * @returns {boolean} 如果栈为空返回true,否则返回false
   */
  isEmpty() {
    return this.items.length === 0;
  }

  /**
   * 5. 获取栈的大小
   * @returns {number} 栈中元素的个数
   */
  size() {
    return this.items.length;
  }
}

// 使用形式
// 创建栈实例
const stack = new Stack();

// 测试栈的基本操作
console.log(stack.isEmpty()); // true
console.log(stack.size());    // 0

// 入栈操作
stack.push(1);
stack.push(2);
stack.push(3);

console.log(stack.size());    // 3
console.log(stack.peek());    // 3 (查看栈顶,不移除)
console.log(stack.isEmpty()); // false

// 出栈操作
console.log(stack.pop());     // 3 (移除并返回栈顶)
console.log(stack.pop());     // 2
console.log(stack.size());    // 1

console.log(stack.peek());    // 1 (当前栈顶)
console.log(stack.pop());     // 1
console.log(stack.isEmpty()); // true
console.log(stack.pop());     // undefined (空栈出栈)

4、获取嵌套对象属性

  • 简单版,只针对对象
function deepGet(obj, path, defaultValue = undefined) {
  // 处理边界情况
  if (!obj || typeof obj !== 'object') return defaultValue;
  if (!path || typeof path !== 'string') return defaultValue;

  // 分割路径并逐级访问
  const keys = path.split('.');
  let result = obj;

  for (let i = 0; i < keys.length; i++) {
    const key = keys[i];

    // 如果当前层级不存在或不是对象,返回默认值
    if (result === null || result === undefined || typeof result !== 'object') {
      return defaultValue;
    }

    result = result[key];
  }

  return result === undefined ? defaultValue : result;
}

// 测试
const obj = {
  a: {
    b: {
      c: 1,
      d: null,
      e: 0,
      f: false,
    },
  },
};

console.log(deepGet(obj, 'a.b.c')); // 1
console.log(deepGet(obj, 'a.b.d')); // null
console.log(deepGet(obj, 'a.b.e')); // 0
console.log(deepGet(obj, 'a.b.f')); // false
console.log(deepGet(obj, 'a.b.x', 'default')); // 'default'
console.log(deepGet(obj, 'x.y.z', 'not found')); // 'not found'
  • 增强版 可以处理数组
function deepGet(obj, path, defaultValue = undefined) {
  if (!obj || typeof path !== 'string') return defaultValue;

  // 处理数组索引,将 'a.b[0].c[1]' 转换为 ['a', 'b', '0', 'c', '1']
  const keys = path
    .replace(/\[(\d+)\]/g, '.$1') // 将 [0] 转换为 .0
    .split('.')
    .filter((key) => key !== ''); // 过滤空字符串

  let result = obj;

  for (const key of keys) {
    if (result === null || result === undefined) {
      return defaultValue;
    }

    // 尝试转换为数字索引(用于数组)
    const index = isNaN(key) ? key : Number(key);
    result = result[index];
  }

  return result === undefined ? defaultValue : result;
}

// 测试数组和对象混合
const complexObj = {
  users: [
    { name: 'Alice', hobbies: ['reading', 'coding'] },
    { name: 'Bob', hobbies: ['gaming', 'music'] },
  ],
  config: {
    settings: {
      theme: 'dark',
      languages: ['zh', 'en'],
    },
  },
};

console.log(deepGet(complexObj, 'users[0].name')); // 'Alice'
console.log(deepGet(complexObj, 'users[1].hobbies[0]')); // 'gaming'
console.log(deepGet(complexObj, 'config.settings.languages[1]')); // 'en'
console.log(deepGet(complexObj, 'users[2].name', 'Unknown')); // 'Unknown'