怎么用自己的主机做网站服务器吗国外免费logo设计网站
2026/2/25 6:35:19 网站建设 项目流程
怎么用自己的主机做网站服务器吗,国外免费logo设计网站,网站建设高级 上海,wordpress keywordJava版LeetCode热题100之最长有效括号#xff1a;三种解法深度剖析与算法思维升华 本文全面解析 LeetCode 第32题「最长有效括号」#xff0c;这是一道考察字符串处理、动态规划、栈应用及双指针技巧的经典难题。文章涵盖题目理解、三种主流解法#xff08;DP、栈、双指针三种解法深度剖析与算法思维升华本文全面解析 LeetCode 第32题「最长有效括号」这是一道考察字符串处理、动态规划、栈应用及双指针技巧的经典难题。文章涵盖题目理解、三种主流解法DP、栈、双指针、代码实现、复杂度分析、面试高频问题、实际应用场景及延伸思考是一篇面向中高级开发者的高质量技术博客。一、原题回顾题目编号LeetCode 32题目名称最长有效括号Longest Valid Parentheses难度等级困难Hard题目描述给你一个只包含(和)的字符串找出最长有效格式正确且连续括号子串的长度。有效括号字符串需满足空字符串是有效的若 A 是有效字符串则 “(A)” 也是有效的若 A 和 B 都是有效字符串则 AB 也是有效的。示例示例 1 输入s (() 输出2 解释最长有效括号子串是 ()位于索引 1-2。 示例 2 输入s )()()) 输出4 解释最长有效括号子串是 ()()位于索引 1-4。 示例 3 输入s 输出0 解释空字符串无有效子串。约束条件0 s.length 3 * 10⁴s[i]为(或)二、原题分析2.1 问题本质本题要求找到最长的连续有效括号子串而非子序列。关键点连续性必须是子串substring不能跳过字符有效性括号必须正确匹配即每个)都有对应的(在其左侧最大化长度只需返回长度不要求具体子串。2.2 直观误区最朴素的想法是枚举所有子串检查是否有效。但时间复杂度为 O(n³)O(n²) 子串 × O(n) 验证对于n30000显然不可行。因此我们需要更高效的策略。本题有三种经典解法动态规划DP记录以每个位置结尾的最长有效长度栈Stack利用栈模拟匹配过程记录边界双指针Two Pass贪心统计左右括号数量正反两次扫描。每种方法都体现了不同的算法思想值得深入学习。三、答案构思方法一 —— 动态规划3.1 核心思想定义dp[i]表示以索引i结尾的最长有效括号子串的长度。关键观察有效子串必以)结尾故若s[i] (则dp[i] 0。3.2 状态转移方程分两种情况讨论s[i] )情况1s[i-1] (→ 形如...()此时s[i-1]和s[i]构成一对有效括号。则dp[i] dp[i-2] 2加上前面的有效长度。注意边界若i 2则dp[i-2]视为 0。情况2s[i-1] )→ 形如...))此时s[i]可能与更早的(匹配。设j i - dp[i-1] - 1即s[i-1]对应的有效子串前一个字符。若s[j] (则s[j]与s[i]匹配形成( ... )结构此时dp[i] dp[i-1] 2 dp[j-1]中间长度 两边长度。注意边界若j 0或s[j] ! (则dp[i] 0。3.3 初始条件与结果初始化dp数组全为 0遍历i从 1 到 n-1因i0时若为)无法匹配最终答案max(dp[0..n-1])四、完整答案方法一动态规划publicclassSolution{publicintlongestValidParentheses(Strings){if(snull||s.length()2){return0;}intns.length();int[]dpnewint[n];// dp[i]: 以i结尾的最长有效长度intmaxLength0;for(inti1;in;i){if(s.charAt(i))){if(s.charAt(i-1)(){// 情况1: ...()dp[i](i2?dp[i-2]:0)2;}else{// 情况2: ...))intji-dp[i-1]-1;// 匹配位置if(j0s.charAt(j)(){dp[i]dp[i-1]2(j1?dp[j-1]:0);}// else: dp[i] 保持 0}maxLengthMath.max(maxLength,dp[i]);}// 若 s[i](dp[i] 保持 0}returnmaxLength;}}代码说明先处理边界长度 2 时直接返回 0显式计算j i - dp[i-1] - 1逻辑清晰使用三元运算符处理边界j-1 0时dp[j-1]0实时更新maxLength。五、代码分析方法一5.1 正确性验证以s )()())为例is[i]dp[i] 计算dp[i] 值0‘)’-01‘(’-02‘)’s[1]‘(’, i2? no → dp[2]02223‘(’-04‘)’s[3]‘(’, i2 → dp[4]dp[2]222445‘)’s[4]‘)’, j5-dp[4]-15-4-10, s[0]‘)’ → 不匹配 → 00✅maxLength 4再看s (()is[i]dp[i]0‘(’01‘(’02‘)’s[1]‘(’, dp[2]dp[0]2022✅ 返回 25.2 边界处理空字符串返回 0单字符返回 0全左括号全 0全右括号全 0有效嵌套如((()))→dp[5]6。六、时间复杂度与空间复杂度分析方法一时间复杂度O(n)单次遍历字符串每次操作O(1)数组访问、比较、加法总计O(n)空间复杂度O(n)dp数组长度为 n总计O(n)对于n30000占用约 120KB 内存30000 × 4 bytes完全可接受。七、答案构思方法二 —— 栈7.1 核心思想利用栈模拟括号匹配过程记录“最后一个未匹配右括号的位置”作为边界。关键技巧初始化栈底为-1统一处理边界。7.2 算法流程初始化栈压入-1遍历字符串遇到(压入当前索引遇到)弹出栈顶尝试匹配若栈空说明当前)无匹配压入当前索引作为新边界否则当前有效长度 i - stack.peek()更新最大值。7.3 为何栈底是“最后一个未匹配右括号”栈中存储的是可能作为左边界的位置当遇到未匹配的)它会成为新的左边界因左边部分已无效栈底始终是最近的无效位置i - stack.peek()即为当前有效长度。八、完整答案方法二栈importjava.util.Deque;importjava.util.LinkedList;publicclassSolution{publicintlongestValidParentheses(Strings){DequeIntegerstacknewLinkedList();stack.push(-1);// 初始化边界intmaxLength0;for(inti0;is.length();i){if(s.charAt(i)(){stack.push(i);}else{stack.pop();// 尝试匹配if(stack.isEmpty()){// 当前 ) 无匹配更新边界stack.push(i);}else{// 计算当前有效长度maxLengthMath.max(maxLength,i-stack.peek());}}}returnmaxLength;}}代码优势逻辑简洁易于理解一次遍历效率高边界处理优雅-1初始化。九、代码分析方法二9.1 执行过程演示以s )()())为例is[i]栈状态底→顶操作maxLength0‘)’[-1] → pop → [] → push(0)[0]01‘(’[0] → push(1)[0,1]02‘)’[0,1] → pop → [0] → i-stack.peek()2-02[0]23‘(’[0] → push(3)[0,3]24‘)’[0,3] → pop → [0] → 4-04[0]45‘)’[0] → pop → [] → push(5)[5]4✅ 返回 49.2 为何初始化为 -1考虑s ()i0: ‘(’ → 栈[-1,0]i1: ‘)’ → pop → 栈[-1] → 长度1 - (-1) 2 ✅若不初始化栈空时无法计算长度。十、时间复杂度与空间复杂度分析方法二时间复杂度O(n)单次遍历每次栈操作O(1)均摊总计O(n)空间复杂度O(n)栈最坏存储所有(即 O(n)总计O(n)与 DP 方法相当但常数更小无需数组初始化。十一、答案构思方法三 —— 双指针O(1) 空间11.1 核心思想贪心统计左右括号数量从左到右当right left时重置计数器因多出的)无法匹配从右到左当left right时重置计数器因多出的(无法匹配。为何需要两次扫描因为单向扫描会漏掉left right始终成立的情况如((())。11.2 算法流程初始化left right 0,maxLength 0从左到右遍历遇(left遇)right若left right更新maxLength max(maxLength, 2*right)若right left重置left right 0从右到左遍历类似条件反转返回maxLength十二、完整答案方法三双指针publicclassSolution{publicintlongestValidParentheses(Strings){intleft0,right0,maxLength0;intns.length();// 从左到右for(inti0;in;i){if(s.charAt(i)(){left;}else{right;}if(leftright){maxLengthMath.max(maxLength,2*right);}elseif(rightleft){leftright0;// 重置}}// 从右到左leftright0;for(intin-1;i0;i--){if(s.charAt(i)(){left;}else{right;}if(leftright){maxLengthMath.max(maxLength,2*left);}elseif(leftright){leftright0;// 重置}}returnmaxLength;}}代码优势空间复杂度 O(1)无需额外数据结构逻辑直观易于实现。十三、代码分析方法三13.1 为何需要两次扫描反例s ((())左到右left3, right2始终leftright不会更新maxLength右到左i4: ‘)’ → right1i3: ‘)’ → right2i2: ‘(’ → left1i1: ‘(’ → left2 →leftright→maxLength4✅13.2 正确性验证s )()())左到右i0: right1left0 → 重置i1-2: left1,right1 → maxLength2i3-4: left2,right2 → maxLength4右到左i5: right1i4: left1 → 1!1? 继续… 最终也会得到 4✅ 返回 4十四、时间复杂度与空间复杂度分析方法三时间复杂度O(n)两次遍历每次 O(n)总计O(n)空间复杂度O(1)仅用几个整型变量总计O(1)这是最优空间解法适合内存受限场景。十五、常见问题解答FAQQ1DP 方法中为何j i - dp[i-1] - 1Adp[i-1]是以i-1结尾的有效长度故有效子串起始位置为i - dp[i-1]。其前一个位置j i - dp[i-1] - 1就是可能与s[i]匹配的(。Q2栈方法中为何弹出后栈空要压入当前索引A因为当前)无匹配它将成为后续有效子串的左边界因左边部分已无效。例如s )()第一个)是边界有效子串从索引 1 开始。Q3双指针方法能否只扫描一次A不能。单向扫描无法处理left right始终成立的情况如((())。必须正反两次才能覆盖所有情形。Q4如果字符串包含其他字符如[,]如何扩展A可用栈记录字符类型或为每种括号维护独立计数器但双指针法难以扩展DP 和栈更通用。十六、优化思路拓展16.1 位运算优化不适用本题涉及顺序和匹配位运算难以建模故不推荐。16.2 并行化由于依赖前序状态难以并行。但若只需求近似解可分段处理后合并非精确。16.3 输出具体子串DP 方法记录maxLength对应的结束位置回溯即可栈方法记录maxLength时的i和stack.peek()即为子串[peek1, i]双指针需额外记录起始位置较复杂。十七、数据结构与算法基础知识点回顾17.1 动态规划状态定义是关键dp[i]表示以i结尾的解分类讨论根据s[i-1]的值分情况转移边界处理防止数组越界。17.2 栈的应用匹配问题括号、HTML标签等边界记录通过栈底存储关键位置单调性本题中栈存储递增索引。17.3 双指针与贪心贪心策略局部最优重置计数器导致全局最优双向扫描处理不对称问题的标准技巧空间优化O(1) 空间的典范。17.4 字符串处理子串 vs 子序列本题要求连续有效性验证通常用栈或计数器。十八、面试官提问环节模拟对话面试官你提到了三种方法各自优缺点是什么答DP思路清晰易扩展如求具体子串但空间 O(n)栈直观模拟匹配空间 O(n)但难扩展到多类型括号双指针空间 O(1)效率高但逻辑稍 tricky且难扩展。面试官栈方法中为什么初始化为 -1 而不是 0答因为当有效子串从索引 0 开始时如()长度 1 - (-1) 2。若初始化为 0则1 - 0 1错误。-1作为虚拟左边界确保计算正确。面试官双指针方法的时间复杂度真的是 O(n) 吗答是的。虽然扫描两次但 2n 仍是 O(n)。常数因子不影响渐进复杂度。面试官如果要求最长有效子序列不要求连续怎么办答那更简单只需统计min(count((), count())) * 2即可因可任意重排。十九、这道算法题在实际开发中的应用19.1 编译器与解释器在语法分析阶段需检测括号是否匹配。本题的栈方法正是编译器中括号检查的核心逻辑。19.2 代码编辑器IDE 的括号高亮、自动补全功能依赖高效的括号匹配算法。最长有效子串可用于提示用户修复范围。19.3 数据格式验证JSON、XML 等格式大量使用括号。解析器需快速定位无效区域本题算法可帮助确定错误位置。19.4 算法竞赛括号序列是经典模型衍生出许多变种如带权重、多类型掌握本题是解决更复杂问题的基础。19.5 生物信息学DNA/RNA 序列中的碱基配对如 A-U, G-C可建模为括号匹配用于预测二级结构。二十、相关题目推荐题号题目关联点20. 有效的括号基础匹配栈应用22. 括号生成生成所有有效序列回溯301. 删除无效的括号修复括号BFS/DFS678. 有效的括号字符串含通配符贪心/双计数器1111. 有效括号的嵌套深度分配括号贪心二十一、总结与延伸21.1 核心收获动态规划通过状态定义解决子串问题栈天然适合匹配类问题边界处理是关键双指针贪心 双向扫描实现 O(1) 空间问题转化从“找子串”到“记录边界/状态”。21.2 延伸思考多类型括号如{[()]}需栈存储类型带权重括号如(a)中a有权重求最大权重有效子串在线版本字符流式到达需动态维护最长有效长度可用栈 段树。21.3 给读者的建议先掌握栈方法因其最直观再学 DP理解状态设计最后看双指针体会空间优化之美面试中可先写栈解法再提及其他方法展示广度。结语最长有效括号是一道集大成的算法题融合了 DP、栈、双指针三大经典技巧。它不仅是 LeetCode 的热门考题更是检验算法基本功的试金石。掌握它你就掌握了处理括号序列问题的通用钥匙。希望本文能助你在技术之路上走得更稳、更远

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询