每天五分钟:双指针-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, height[i]) 。

找出其中的两条线,使得它们与 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], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 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
相关推荐
数智工坊13 分钟前
【操作系统-文件管理】
数据结构·数据库
龙山云仓30 分钟前
No131:AI中国故事-对话荀子——性恶论与AI约束:礼法并用、化性起伪与算法治理
大数据·人工智能·深度学习·算法·机器学习
夏鹏今天学习了吗38 分钟前
【LeetCode热题100(90/100)】编辑距离
算法·leetcode·职场和发展
芒克芒克1 小时前
数组去重进阶:一次遍历实现最多保留指定个数重复元素(O(n)时间+O(1)空间)
数据结构·算法
星火开发设计1 小时前
二维数组:矩阵存储与多维数组的内存布局
开发语言·c++·人工智能·算法·矩阵·函数·知识
Fcy6482 小时前
⽤哈希表封装unordered_map和unordered_set(C++模拟实现)
数据结构·c++·散列表
丨康有为丨2 小时前
算法时间复杂度和空间复杂度
算法
HarmonLTS2 小时前
Python人工智能深度开发:技术体系、核心实践与工程化落地
开发语言·人工智能·python·算法
a程序小傲2 小时前
京东Java面试被问:RPC调用的熔断降级和自适应限流
java·开发语言·算法·面试·职场和发展·rpc·边缘计算
一分之二~2 小时前
二叉树--层序遍历(迭代和递归)
数据结构·c++·算法·leetcode