每天五分钟:双指针-LeetCode高频题_解析

283. 移动零https://leetcode.cn/problems/move-zeroes/

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

python 复制代码
输入: nums = [0,1,0,3,12]

输出: [1,3,12,0,0

⭐ 本题使用的是"双指针 · 同向指针(slow/fast)"

  • right 指针(fast):遍历数组,寻找所有非零数字

  • left 指针(slow):指向下一个应该放非零数字的位置

复制代码
初始数组:
[0, 1, 0, 3, 12]
 L
 R

1️⃣ R=0,nums[0] = 0 → 不动
[0, 1, 0, 3, 12]
 L
 R
2️⃣ R=1,nums[1] = 1 → 和 L(=0) 交换

[1, 0, 0, 3, 12]
    L
    R
3️⃣ R=2,nums[2] = 0 → 不动

[1, 0, 0, 3, 12]
    L
       R
4️⃣ R=3,nums[3] = 3 → 与 L(=1) 交换

[1, 3, 0, 0, 12]
       L
          R
5️⃣ R=4,nums[4] = 12 → 与 L(=2) 交换

[1, 3, 12, 0, 0]
          L
             R

最终结果:

[1, 3, 12, 0, 0]

python代码如下:

python 复制代码
class Solution:
    def moveZeroes(self, nums):
        left, right = 0, 0
        while right < len(nums):
            if nums[right] != 0:
                nums[left], nums[right] = nums[right], nums[left]
                left += 1
            right += 1

11. 盛最多水的容器https://leetcode.cn/problems/container-with-most-water/

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和(i, heighti) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

⭐ 本题使用的是"双指针 · 对撞指针"

1. 定义两个指针

left 指向最左边的木板(0) right 指向最右边的木板(n-1)

2. 当前这两块木板能装多少水?

python 复制代码
width = right - left 
height_container = min(height[left], height[right]) 
area = width * height_container

用一个变量 max_area 记录最大值。

3. 关键问题:下一步应该动谁?

只有移动矮板,才可能出现更高的短板,增加面积

python 复制代码
left = 0, right = n - 1, max_area = 0

当 left < right 时循环:

计算当前面积:
area = (right - left) * min(height[left], height[right])

更新 max_area

如果 height[left] < height[right]:
left += 1

否则:
right -= 1

循环结束,返回 max_area

python代码如下:

python 复制代码
class Solution:
    def maxArea(self, height):
        left, right = 0, len(height) - 1
        max_area = 0

        while left < right:
            # 当前容器宽度
            width = right - left
            # 短板高度
            h = min(height[left], height[right])
            # 当前面积
            area = width * h
            # 更新最大值
            max_area = max(max_area, area)

            # 谁矮谁挪窝
            if height[left] < height[right]:
                left += 1
            else:
                right -= 1

        return max_area

15. 三数之和https://leetcode.cn/problems/3sum/

给你一个整数数组 nums ,判断是否存在三元组 nums\[i, numsj, numsk] 满足 i != j、i != k 且 j != k ,同时还满足 numsi + numsj + numsk == 0 。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

python 复制代码
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

⭐ 本题使用的是 排序+"双指针 · 对撞指针"

想象一个场景:

有一条队伍,队伍里站着很多同学,每个同学手里拿着一个"分数",可能是负的,也可能是正的。

老师的任务是:

"在这堆同学里,找出所有 三人小组

让他们手里的分数加起来 刚好等于 0

而且 同样的三人组合不能算两次。"

  1. 先让同学按分数从小到大排好队(排序)

  2. 接着,老师做下面的事:

    • 从左到右,一个一个选"第一个同学"当队长(下标 i)

    • 然后在他右边,用两只手:

      • 左手指向队长右边第一个人(left)

      • 右手指向队伍最后一个人(right)

    • 这三个同学(队长、left、right)的分数之和:

      • 如果 太小了(<0) :说明分数不够,需要更大一点

        👉 左手往右挪一步(left++)

      • 如果 太大了(>0) :说明分数太大,需要小一点

        👉 右手往左挪一步(right--)

      • 如果 刚好等于 0

        👉 记录下这组三人组

        👉 然后左右手都挪一格,继续找下一组

并且,老师还有一个要求:"如果遇到 一模一样的分数的同学,同样的选法就不再重复试一遍(去重)。"

就这样,把原本需要三重循环才能做的事情,用两重循环就搞定了。

python代码如下:

python 复制代码
class Solution:
    def threeSum(self, nums):
        nums.sort()          # 1. 先排序
        n = len(nums)
        res = []

        for i in range(n):
            # 剪枝1:如果第一个数已经 > 0,后面更不可能凑成 0
            if nums[i] > 0:
                break

            # 去重1:跳过相同的起点
            if i > 0 and nums[i] == nums[i - 1]:
                continue

            left, right = i + 1, n - 1

            while left < right:
                s = nums[i] + nums[left] + nums[right]

                if s < 0:
                    # 总和太小,左指针右移,让和变大
                    left += 1
                elif s > 0:
                    # 总和太大,右指针左移,让和变小
                    right -= 1
                else:
                    # 找到一个三元组
                    res.append([nums[i], nums[left], nums[right]])

                    # 去重2:跳过相同的 left
                    while left < right and nums[left] == nums[left + 1]:
                        left += 1
                    # 去重3:跳过相同的 right
                    while left < right and nums[right] == nums[right - 1]:
                        right -= 1

                    # 移动到下一对
                    left += 1
                    right -= 1

        return res
相关推荐
kkeeper~6 小时前
0基础C语言积跬步之数据在内存中的存储
c语言·数据结构·算法
2401_868534787 小时前
论企业网络设计
数据结构
wabs6668 小时前
关于贪心算法的一些自我总结【力扣45.跳跃游戏II】【灵感来源:代码随想录】
算法·贪心算法·复盘
2401_876964138 小时前
【湖北专升本】2026湖北专升本真题PDF+备考资料汇总
数据结构·人工智能·经验分享·深度学习·算法·计算机视觉
嗝o゚9 小时前
CANN GE 算子融合——融合算法与调度策略
算法·昇腾·cann·ge
小江的记录本9 小时前
【JVM虚拟机】垃圾回收GC:垃圾回收算法:标记-清除、标记-复制、标记-整理、分代收集(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·算法·安全·面试
Ulyanov10 小时前
用声明式语法重新定义Python桌面UI:QML+PySide6现代开发入门(一)
开发语言·python·算法·ui·系统仿真·雷达电子对抗仿真
数据科学小丫10 小时前
特征工程处理
人工智能·算法·机器学习
z落落11 小时前
C#参数区别
java·算法·c#
c2385612 小时前
vector(下)
数据结构·算法