news 2026/11/2 2:56:10

力扣三题精解:双指针与数组操作实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
力扣三题精解:双指针与数组操作实战

1. 力扣三题精解:颜色分类、下一个排列与寻找重复数

刷算法题是程序员提升基本功的必经之路,而力扣(LeetCode)作为全球知名的编程题库,其题目质量与分类体系深受开发者认可。今天我想分享三道中等难度的经典题目:75.颜色分类、31.下一个排列和287.寻找重复数。这三题分别考察了双指针技巧、数组排列规律和环形链表检测思想,都是面试中的高频考点。

我在实际刷题过程中发现,这三道题虽然表面看起来毫不相关,但背后都隐藏着对数组操作的深刻理解。掌握它们不仅能帮助你在面试中游刃有余,更能提升对基础数据结构的敏感度。下面我将从问题分析、解法思路到具体实现,一步步拆解这三道题目,并分享一些只有实际编码才能获得的经验技巧。

2. 75.颜色分类:荷兰国旗问题实战

2.1 问题重述与初步分析

题目要求我们原地对一个只包含0、1、2的数组进行排序,使得所有0排在前面,1在中间,2在最后。这其实就是著名的荷兰国旗问题(Dutch National Flag Problem),由计算机科学家Edsger Dijkstra提出。

关键约束条件:

  • 必须原地排序(空间复杂度O(1))
  • 只能遍历数组一次(时间复杂度O(n))
  • 不能使用库的排序函数

注意:原地排序意味着不能使用额外空间创建新数组,这对算法设计提出了更高要求。

2.2 双指针解法详解

最优雅的解法是使用三指针技巧,这也是面试官最希望看到的解决方案。具体思路如下:

  1. 初始化三个指针:

    • left:指向当前0的右边界(初始为0)
    • right:指向当前2的左边界(初始为len(nums)-1)
    • current:当前遍历指针(初始为0)
  2. 遍历规则:

    • 当nums[current] == 0:与left交换,left++,current++
    • 当nums[current] == 1:直接current++
    • 当nums[current] == 2:与right交换,right--(注意此时不移动current)
def sortColors(nums): left, current, right = 0, 0, len(nums) - 1 while current <= right: if nums[current] == 0: nums[left], nums[current] = nums[current], nums[left] left += 1 current += 1 elif nums[current] == 1: current += 1 else: nums[current], nums[right] = nums[right], nums[current] right -= 1

2.3 关键点与易错分析

  1. 指针移动的边界条件:

    • 与left交换后可以安全地移动current,因为left指向的元素已经被处理过
    • 但与right交换后不能移动current,因为从右边交换过来的元素尚未被检查
  2. 时间复杂度分析:

    • 每个元素最多被交换两次(一次到左边,一次到右边)
    • 总体时间复杂度严格O(n)
  3. 常见错误:

    • 忘记处理current > right的终止条件
    • 在交换2之后错误地移动current指针
    • 边界条件处理不当导致数组越界

3. 31.下一个排列:字典序排列的奥秘

3.1 排列的数学定义

"下一个排列"指的是在当前排列的字典序中,比当前排列大的最小排列。例如:

  • 1,2,3 → 1,3,2
  • 3,2,1 → 1,2,3(因为是循环的)

理解字典序的关键是认识到排列可以看作一个数字,下一个排列就是"比当前数字大的最小数字"。

3.2 算法步骤拆解

解决这个问题的标准算法步骤如下:

  1. 从后向前查找第一个降序对:找到第一个满足nums[i] < nums[i+1]的i
  2. 如果找不到,说明已经是最大排列,直接反转整个数组
  3. 否则,从后向前找到第一个大于nums[i]的元素nums[j]
  4. 交换nums[i]和nums[j]
  5. 反转i+1到末尾的部分
def nextPermutation(nums): n = len(nums) i = n - 2 while i >= 0 and nums[i] >= nums[i+1]: i -= 1 if i >= 0: j = n - 1 while j >= 0 and nums[j] <= nums[i]: j -= 1 nums[i], nums[j] = nums[j], nums[i] left, right = i+1, n-1 while left < right: nums[left], nums[right] = nums[right], nums[left] left += 1 right -= 1

3.3 实战技巧与注意事项

  1. 为什么从后向前查找:

    • 字典序的变化总是从低位开始
    • 这样可以确保找到的是"最小"的更大排列
  2. 反转而不是排序:

    • 在找到i之后,i+1到末尾的部分一定是降序的
    • 反转这部分可以达到升序效果,且时间复杂度O(n)优于排序的O(nlogn)
  3. 边界情况处理:

    • 空数组或单元素数组直接返回
    • 全降序数组需要特殊处理

4. 287.寻找重复数:龟兔赛跑的精妙应用

4.1 问题描述与约束

给定一个包含n+1个整数的数组nums,其中每个整数都在[1,n]范围内,根据鸽巢原理至少有一个重复数字。要求:

  • 不能修改原数组(不能排序或标记)
  • 只能使用O(1)的额外空间
  • 时间复杂度低于O(n²)

这实际上把暴力解法、排序法和哈希表法都排除了,必须寻找更聪明的办法。

4.2 Floyd判圈算法解析

这个问题可以转化为链表中的环检测问题,使用快慢指针(Floyd's Tortoise and Hare算法):

  1. 将数组视为链表:nums[i]表示i指向的下一个节点
  2. 因为有重复数字,所以必然存在环
  3. 使用快指针(每次两步)和慢指针(每次一步)找到相遇点
  4. 然后从头开始,直到再次相遇即为重复数字
def findDuplicate(nums): slow = fast = nums[0] while True: slow = nums[slow] fast = nums[nums[fast]] if slow == fast: break slow = nums[0] while slow != fast: slow = nums[slow] fast = nums[fast] return slow

4.3 为什么这个方法有效

这个算法的精妙之处在于:

  1. 第一阶段:快慢指针一定会相遇,因为存在环
  2. 第二阶段:从头开始的指针和相遇点指针以相同速度移动,最终会在环入口(重复数字)相遇

数学证明:

  • 设环外长度为L,环长度为C
  • 相遇时慢指针走了L+D,快指针走了2(L+D)=L+D+kC
  • 可得L+D=kC ⇒ L=(k-1)C+(C-D)
  • 因此从起点和相遇点同时出发,必在入口相遇

5. 三题对比与刷题心得

虽然这三道题看似不同,但它们都体现了算法设计的几个核心思想:

  1. 指针技巧的灵活运用:

    • 颜色分类:三指针分区
    • 下一个排列:双指针查找与反转
    • 寻找重复数:快慢指针检测环
  2. 对问题本质的深刻理解:

    • 将排序问题转化为指针移动
    • 将排列问题转化为字典序变化规律
    • 将查找问题转化为链表环检测
  3. 边界条件的严格处理:

    • 每个问题都有容易忽略的边界情况
    • 必须通过大量测试用例验证

我在实际刷题中发现,中等难度的题目往往需要:

  • 先理解问题本质,不要急于编码
  • 画图辅助理解指针移动或数据流动
  • 写出伪代码理清思路再实现
  • 特别注意循环不变量的维护

最后分享一个实用技巧:对于这类数组操作问题,可以先用小规模例子(如3-5个元素)手动模拟算法过程,这能帮助快速发现思路中的漏洞。记住,在面试中清晰的解题思路比直接写代码更重要。

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

智能机械爪与微信对话系统的AI助手开发实践

1. 项目概述&#xff1a;当机械爪遇上智能对话去年在深圳Maker Faire上&#xff0c;我第一次看到OpenClaw机械爪抓取积木的演示&#xff0c;当时就萌生了个想法&#xff1a;如果给这个灵活的机械臂装上"大脑"&#xff0c;让它能理解人类语言会怎样&#xff1f;三个月…

作者头像 李华
网站建设 2026/11/2 2:55:46

MCP本地服务链实战:从单Server到多工具编排与调试避坑

AI 会写代码、能改文案&#xff0c;可一旦你让它"看看我本地这个项目为什么跑不起来"或者"把我桌面上那份表格的第二列汇总一下"&#xff0c;它立刻变哑巴——因为模型本身没有手&#xff0c;也没有眼睛&#xff0c;它只能看见你粘贴进对话框的那点文字。M…

作者头像 李华
网站建设 2026/11/2 2:55:33

设计模式分类解析:从GoF到云原生的演进与实践

1. 设计模式分类的底层逻辑设计模式的分类从来就不是随意为之&#xff0c;而是基于软件工程中反复出现的核心问题域。我第一次系统学习设计模式是在2013年参与一个电商平台重构项目时&#xff0c;当时面对错综复杂的订单处理流程&#xff0c;导师扔给我一本《设计模式&#xff…

作者头像 李华
网站建设 2026/11/2 2:54:41

Transformer可视化工具:透视数据流,击碎学习中的抽象壁垒

经常遇到读者问&#xff0c;Transformer 到底怎么学&#xff1f;我的答案从来都是&#xff1a;别只看结构图&#xff0c;找个能看见数据流动的工具&#xff0c;亲手跑一遍。这个想法促使我做了个 Transformer 可视化工具&#xff0c;用下来之后发现&#xff0c;之前那些“好像懂…

作者头像 李华
网站建设 2026/11/2 2:53:10

库卡KRC4 KPS600电源模块故障诊断:LED码、保险与KCP信息窗口排查

简介&#xff1a;这份手册围绕库卡KRC4机器人KPS600电源模块的故障排查与维护展开&#xff0c;面向工业机器人电气维护人员、现场调试工程师及自动化专业学习者&#xff0c;帮助其在设备报警停机时快速定位电源与驱动环节的问题。压缩包内为1个PDF文档&#xff0c;约958KB&…

作者头像 李华
网站建设 2026/11/2 2:51:22

计算机实战学习平台架构与微服务技术解析

1. 项目概述&#xff1a;一站式计算机与工程类实战学习平台"百考通"是一个面向计算机与工程类专业学生的综合性实战项目学习平台。不同于传统理论教学网站&#xff0c;这个平台的核心价值在于提供大量真实行业项目案例&#xff0c;覆盖从Web开发到嵌入式系统的全技术…

作者头像 李华