前端算法类型

63 阅读4分钟

前端面试算法类型

1. 数组与字符串

1.1 数组题目

  • 求最大/最小值:通常可以使用一次遍历来找到最大或最小值。

    • 示例:求数组中的最大值
      function findMax(arr) {
        return Math.max(...arr);
      }
      
  • 排序:可以使用内置的排序方法或者实现常见的排序算法(如快速排序、归并排序)。

    • 示例:数组排序
      function sortArray(arr) {
        return arr.sort((a, b) => a - b);
      }
      
  • 查找重复元素:可以使用哈希表来记录出现的元素。

    • 示例:查找数组中的重复元素
      function findDuplicates(arr) {
        let seen = new Set();
        let duplicates = new Set();
        for (let num of arr) {
          if (seen.has(num)) {
            duplicates.add(num);
          } else {
            seen.add(num);
          }
        }
        return [...duplicates];
      }
      
  • 滑动窗口:用于处理固定长度的子数组或子字符串问题。

    • 示例:找到和为定值的连续子数组
      function subarraySum(arr, target) {
        let sum = 0;
        let map = new Map();
        map.set(0, -1);
        for (let i = 0; i < arr.length; i++) {
          sum += arr[i];
          if (map.has(sum - target)) {
            return [map.get(sum - target) + 1, i];
          }
          map.set(sum, i);
        }
        return [];
      }
      

1.2 字符串题目

  • 反转字符串:可以通过双指针或内置方法来实现。

    • 示例:反转字符串
      function reverseString(str) {
        return str.split('').reverse().join('');
      }
      
  • 判断回文:通过双指针比较字符串的两端。

    • 示例:判断字符串是否为回文
      function isPalindrome(str) {
        let left = 0;
        let right = str.length - 1;
        while (left < right) {
          if (str[left] !== str[right]) {
            return false;
          }
          left++;
          right--;
        }
        return true;
      }
      
  • 最长子串:使用滑动窗口或动态规划。

    • 示例:找到最长不含重复字符的子串
      function lengthOfLongestSubstring(s) {
        let map = new Map();
        let maxLen = 0;
        let start = 0;
        for (let end = 0; end < s.length; end++) {
          if (map.has(s[end])) {
            start = Math.max(map.get(s[end]) + 1, start);
          }
          map.set(s[end], end);
          maxLen = Math.max(maxLen, end - start + 1);
        }
        return maxLen;
      }
      

2. 链表

  • 反转链表:使用迭代或递归。

    • 示例:反转链表
      function reverseList(head) {
        let prev = null;
        let curr = head;
        while (curr) {
          let nextTemp = curr.next;
          curr.next = prev;
          prev = curr;
          curr = nextTemp;
        }
        return prev;
      }
      
  • 链表中环的检测:使用快慢指针。

    • 示例:判断链表中是否有环
      function hasCycle(head) {
        let slow = head;
        let fast = head;
        while (fast && fast.next) {
          slow = slow.next;
          fast = fast.next.next;
          if (slow === fast) {
            return true;
          }
        }
        return false;
      }
      

3. 栈与队列

  • 有效的括号:使用栈来匹配括号。

    • 示例:有效的括号
      function isValid(s) {
        let stack = [];
        let map = {
          '(': ')',
          '{': '}',
          '[': ']'
        };
        for (let char of s) {
          if (char in map) {
            stack.push(char);
          } else {
            if (char !== map[stack.pop()]) {
              return false;
            }
          }
        }
        return stack.length === 0;
      }
      
  • 队列实现栈:用两个队列来模拟栈的操作。

    • 示例:用队列实现栈
      class MyStack {
        constructor() {
          this.queue1 = [];
          this.queue2 = [];
        }
      
        push(x) {
          this.queue1.push(x);
        }
      
        pop() {
          while (this.queue1.length > 1) {
            this.queue2.push(this.queue1.shift());
          }
          let popped = this.queue1.shift();
          let temp = this.queue1;
          this.queue1 = this.queue2;
          this.queue2 = temp;
          return popped;
        }
      
        top() {
          return this.queue1[this.queue1.length - 1];
        }
      
        empty() {
          return this.queue1.length === 0;
        }
      }
      

4. 树与图

4.1 树

  • 二叉树的遍历:包括前序遍历、中序遍历和后序遍历。

    • 示例:前序遍历
      function preorderTraversal(root) {
        let result = [];
        function traverse(node) {
          if (!node) return;
          result.push(node.val);
          traverse(node.left);
          traverse(node.right);
        }
        traverse(root);
        return result;
      }
      
  • 二叉树的层序遍历:使用队列实现。

    • 示例:层序遍历
      function levelOrder(root) {
        let result = [];
        if (!root) return result;
        let queue = [root];
        while (queue.length) {
          let level = [];
          let size = queue.length;
          for (let i = 0; i < size; i++) {
            let node = queue.shift();
            level.push(node.val);
            if (node.left) queue.push(node.left);
            if (node.right) queue.push(node.right);
          }
          result.push(level);
        }
        return result;
      }
      

4.2 图

  • 深度优先搜索(DFS):递归实现或使用栈。

    • 示例:DFS
      function dfs(graph, start) {
        let visited = new Set();
        function traverse(node) {
          if (visited.has(node)) return;
          visited.add(node);
          for (let neighbor of graph[node]) {
            traverse(neighbor);
          }
        }
        traverse(start);
        return visited;
      }
      
  • 广度优先搜索(BFS):使用队列。

    • 示例:BFS
      function bfs(graph, start) {
        let visited = new Set();
        let queue = [start];
        while (queue.length) {
          let node = queue.shift();
          if (visited.has(node)) continue;
          visited.add(node);
          for (let neighbor of graph[node]) {
            queue.push(neighbor);
          }
        }
        return visited;
      }
      

5. 动态规划

  • 斐波那契数列:使用递归或动态规划。

    • 示例:斐波那契数列
      function fib(n) {
        let dp = [0, 1];
        for (let i = 2; i <= n; i++) {
          dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
      }
      
  • 背包问题:经典的动态规划问题。

    • 示例:0/1 背包问题
      function knapsack(weights, values, capacity) {
        let n = weights.length;
        let dp = Array.from({ length: n + 1 }, () => Array(capacity + 1).fill(0));
        for (let i = 1; i <= n; i++) {
          for (let w = 1; w <= capacity; w++) {
            if (weights[i - 1] <= w) {
              dp[i][w] = Math.max(dp[i - 1][w], dp[i - 1][w - weights[i - 1]] + values[i - 1]);
            } else {
              dp[i][w] = dp[i - 1][w];
            }
          }
        }
        return dp[n][capacity];
      }
      

6. 贪心算法

  • 找零钱问题:通过贪心策略选择最大的面额。
    • 示例:找零钱
      function coinChange(coins,
      

amount) { let count = 0; coins.sort((a, b) => b - a); for (let coin of coins) { if (amount >= coin) { count += Math.floor(amount / coin); amount %= coin; } } return amount === 0 ? count : -1; } ```

7. 回溯算法

  • 全排列:使用回溯生成所有可能的排列。
    • 示例:全排列
      function permute(nums) {
        let result = [];
        function backtrack(path, used) {
          if (path.length === nums.length) {
            result.push([...path]);
            return;
          }
          for (let i = 0; i < nums.length; i++) {
            if (used[i]) continue;
            path.push(nums[i]);
            used[i] = true;
            backtrack(path, used);
            path.pop();
            used[i] = false;
          }
        }
        backtrack([], Array(nums.length).fill(false));
        return result;
      }
      

8. 数学与位运算

  • 素数判断:常用于数论问题。

    • 示例:判断素数
      function isPrime(num) {
        if (num <= 1) return false;
        if (num <= 3) return true;
        if (num % 2 === 0 || num % 3 === 0) return false;
        for (let i = 5; i * i <= num; i += 6) {
          if (num % i === 0 || num % (i + 2) === 0) return false;
        }
        return true;
      }
      
  • 位运算:处理位级操作,如与、或、异或、左移、右移等。

    • 示例:计算二进制中1的个数
      function hammingWeight(n) {
        let count = 0;
        while (n !== 0) {
          count += n & 1;
          n >>>= 1;
        }
        return count;
      }