news 2026/8/22 5:18:25

前端算法实战:高频面试题解析与最优解法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
前端算法实战:高频面试题解析与最优解法

1. 前端算法实战:从零手撕高频面试题

作为一名经历过多次大厂面试的前端工程师,我深知算法能力在前端面试中的重要性。很多人认为前端不需要算法,但现实是各大厂的前端岗位面试中,算法题占比越来越高。今天我就来分享几个前端面试中最常考的算法题,带你从零理解解题思路,掌握最优解法。

2. 无重复字符的最长子串

2.1 问题分析

给定一个字符串,找出其中不含有重复字符的最长子串的长度。例如:

  • 输入:"abcabcbb",输出:3("abc")
  • 输入:"bbbbb",输出:1("b")

2.2 滑动窗口解法

最优解法是滑动窗口(双指针)算法,时间复杂度O(n):

var lengthOfLongestSubstring = function(s) { const charIndexMap = new Map(); let left = 0; let maxLength = 0; for (let right = 0; right < s.length; right++) { const currentChar = s[right]; if (charIndexMap.has(currentChar) && charIndexMap.get(currentChar) >= left) { left = charIndexMap.get(currentChar) + 1; } charIndexMap.set(currentChar, right); maxLength = Math.max(maxLength, right - left + 1); } return maxLength; };

2.3 关键点解析

  1. charIndexMap:记录字符最后出现的位置
  2. 左指针移动:只有当重复字符在当前窗口内时才移动
  3. 窗口长度计算:right - left + 1

注意事项:处理"abba"这类情况时,左指针不能回退,必须确保left只向右移动

3. 比较版本号

3.1 问题描述

比较两个版本号version1和version2:

  • 如果version1 > version2,返回1
  • 如果version1 < version2,返回-1
  • 否则返回0

3.2 拆分+补零解法

var compareVersion = function(version1, version2) { const v1Arr = version1.split('.'); const v2Arr = version2.split('.'); const maxLen = Math.max(v1Arr.length, v2Arr.length); for (let i = 0; i < maxLen; i++) { const num1 = i < v1Arr.length ? parseInt(v1Arr[i], 10) : 0; const num2 = i < v2Arr.length ? parseInt(v2Arr[i], 10) : 0; if (num1 > num2) return 1; if (num1 < num2) return -1; } return 0; };

3.3 核心技巧

  1. split('.'):正确拆分版本号
  2. parseInt:自动忽略前导零
  3. 补零处理:短版本号缺失部分视为0

4. 合并两个有序数组

4.1 逆向双指针解法

从后往前合并,避免覆盖nums1的元素:

var merge = function(nums1, m, nums2, n) { let p1 = m - 1; let p2 = n - 1; let p = m + n - 1; while (p1 >= 0 && p2 >= 0) { nums1[p--] = nums1[p1] >= nums2[p2] ? nums1[p1--] : nums2[p2--]; } while (p2 >= 0) { nums1[p--] = nums2[p2--]; } };

4.2 关键点

  1. 三指针初始化:p1指向nums1有效末尾,p2指向nums2末尾
  2. 从后往前填充:避免元素覆盖
  3. 处理剩余元素:只需处理nums2剩余情况

5. 有效的括号

5.1 栈的应用

var isValid = function(s) { const bracketMap = { ')': '(', '}': '{', ']': '[' }; const stack = []; for (let char of s) { if (char in bracketMap) { if (stack.length === 0 || stack.pop() !== bracketMap[char]) { return false; } } else { stack.push(char); } } return stack.length === 0; };

5.2 注意事项

  1. 右括号映射:使用对象快速查找对应左括号
  2. 栈空检查:遇到右括号时栈不能为空
  3. 最终栈检查:遍历结束后栈必须为空

6. 字符串相加

6.1 模拟手工加法

var addStrings = function(num1, num2) { let i = num1.length - 1; let j = num2.length - 1; let carry = 0; const result = []; while (i >= 0 || j >= 0 || carry > 0) { const digit1 = i >= 0 ? Number(num1[i--]) : 0; const digit2 = j >= 0 ? Number(num2[j--]) : 0; const sum = digit1 + digit2 + carry; result.push(sum % 10); carry = Math.floor(sum / 10); } return result.reverse().join(''); };

6.2 关键步骤

  1. 从末尾开始相加:模拟手工计算
  2. 处理进位:carry记录进位值
  3. 结果反转:因为是从个位开始存储

7. 两数之和

7.1 哈希表最优解

var twoSum = function(nums, target) { const map = new Map(); for (let i = 0; i < nums.length; i++) { const complement = target - nums[i]; if (map.has(complement)) { return [map.get(complement), i]; } map.set(nums[i], i); } return []; };

7.2 性能对比

方法时间复杂度空间复杂度
暴力法O(n²)O(1)
哈希表法O(n)O(n)

8. 全排列

8.1 回溯算法

var permute = function(nums) { const result = []; const path = []; const used = new Array(nums.length).fill(false); const backtrack = () => { 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.pop(); used[i] = false; } }; backtrack(); return result; };

8.2 回溯三要素

  1. 选择:将元素加入路径
  2. 递归:继续选择下一个元素
  3. 撤销:回溯到上一步

9. 反转链表

9.1 迭代法

var reverseList = function(head) { let prev = null; let curr = head; while (curr !== null) { const nextTemp = curr.next; curr.next = prev; prev = curr; curr = nextTemp; } return prev; };

9.2 递归法

var reverseList = function(head) { if (head === null || head.next === null) { return head; } const newHead = reverseList(head.next); head.next.next = head; head.next = null; return newHead; };

10. 二叉树层序遍历

10.1 BFS实现

var levelOrder = function(root) { if (!root) return []; const result = []; const queue = [root]; while (queue.length) { const levelSize = queue.length; const currentLevel = []; for (let i = 0; i < levelSize; i++) { const node = queue.shift(); currentLevel.push(node.val); if (node.left) queue.push(node.left); if (node.right) queue.push(node.right); } result.push(currentLevel); } return result; };

10.2 关键点

  1. 队列管理:先进先出处理节点
  2. 层级记录:通过levelSize确保按层处理
  3. 子节点入队:左节点先入队

11. 最大子数组和

11.1 Kadane算法

var maxSubArray = function(nums) { let currentSum = nums[0]; let maxSum = nums[0]; for (let i = 1; i < nums.length; i++) { currentSum = Math.max(nums[i], currentSum + nums[i]); maxSum = Math.max(maxSum, currentSum); } return maxSum; };

11.2 算法思想

  • 当前和为负则抛弃
  • 当前和为正则保留
  • 始终维护全局最大值

12. 三数之和

12.1 排序+双指针

var threeSum = function(nums) { const result = []; nums.sort((a, b) => a - b); const n = nums.length; for (let i = 0; i < n; i++) { if (i > 0 && nums[i] === nums[i - 1]) continue; let left = i + 1; let right = n - 1; while (left < right) { const sum = nums[i] + nums[left] + nums[right]; if (sum === 0) { result.push([nums[i], nums[left], nums[right]]); while (left < right && nums[left] === nums[left + 1]) left++; while (left < right && nums[right] === nums[right - 1]) right--; left++; right--; } else if (sum < 0) { left++; } else { right--; } } } return result; };

12.2 去重技巧

  1. 排序:便于跳过重复元素
  2. 固定数去重:nums[i] === nums[i-1]时跳过
  3. 双指针去重:找到解后跳过相同left/right

13. 算法学习建议

  1. 分类练习:按算法类型(双指针、DFS、DP等)集中突破
  2. 手写实现:理解后自己实现,不要直接看答案
  3. 复杂度分析:养成分析时间/空间复杂度的习惯
  4. 反复练习:高频题目要多次练习达到熟练

在实际面试中,面试官不仅考察你能不能解出题目,更看重解题思路的清晰度和代码实现的规范性。建议在练习时注意代码风格,添加必要注释,展现良好的编程习惯。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/22 5:16:41

Magic-API:基于Spring Boot的SQL直出HTTP接口方案

1. 这不是又一个API管理工具&#xff0c;而是一次开发范式的位移Magic-API 这个名字刚出来的时候&#xff0c;我第一反应是“又一个带 magic 的营销词”&#xff0c;点开文档扫了三分钟&#xff0c;手就停不下来了——它根本不是在帮你“管理”API&#xff0c;而是直接绕过 Con…

作者头像 李华
网站建设 2026/8/22 5:15:35

LangGraph.js:构建可中断、可恢复的AI工作流与智能体

1. 从LangChain到LangGraph&#xff1a;为什么我们需要“可中断”的AI工作流&#xff1f;如果你在过去一两年里折腾过AI应用开发&#xff0c;尤其是基于大语言模型&#xff08;LLM&#xff09;构建一些自动化流程&#xff0c;那么“LangChain”这个名字你一定不陌生。它像是一套…

作者头像 李华
网站建设 2026/8/22 5:15:19

Java集合类面试解析:HashMap与ArrayList核心原理

1. 面试背景与问题还原最近参加了一场互联网大厂的Java技术面试&#xff0c;遇到了一位自称"谢飞机"的候选人。这位同学的答题方式堪称行为艺术&#xff0c;把常见的Java集合问题回答出了新高度。以下是几个典型问题的复盘&#xff0c;我会结合HashMap、ArrayList、L…

作者头像 李华
网站建设 2026/8/22 5:14:46

基于Vorflux AI的智能体代码安全审查:实战沙盒隔离与自动化验证

在智能体开发如火如荼的今天&#xff0c;我们常常面临一个核心痛点&#xff1a;如何确保智能体生成的代码或脚本&#xff0c;在真实的生产环境中是安全、可靠且能正确执行的&#xff1f;无论是基于 LangGraph 构建的本地 AI 智能体&#xff0c;还是使用 Dify、Coze 等平台开发的…

作者头像 李华
网站建设 2026/8/22 5:14:00

一台内网 GPU 全科室共用:Ollama 校对引擎部署记

科室八个人都要用 AI 校对&#xff0c;但机器是涉密内网&#xff0c;外网一个包都进不来&#xff1b;全科室只有一台机器有 GPU。这是上个月我接到的活。最后落地方案&#xff1a;那台 GPU 机器跑 Ollama 当推理底座&#xff0c;全科室共用&#xff0c;所有人 WPS 里的察元AI文…

作者头像 李华
网站建设 2026/8/22 5:12:24

IEEE 754浮点数运算:加法与乘法的性质、误差与工程实践

你有没有遇到过这样的场景&#xff1a;写了一段看似简单的数值计算代码&#xff0c;比如0.1 0.2&#xff0c;结果打印出来不是0.3&#xff0c;而是0.30000000000000004&#xff1f;或者&#xff0c;在一个循环里累加一个很小的浮点数&#xff0c;期望得到一个精确的总和&#…

作者头像 李华