当前位置: 首页 > news >正文

Leetcode刷题报告2——双指针法

文章目录

    • 前言
    • [15. 三数之和](https://leetcode.cn/problems/3sum/)
      • 题干
      • 题解
      • 知识点总结
    • [42. 接雨水](https://leetcode.cn/problems/trapping-rain-water/)
      • 题干
      • 题解

前言

这部分总共是4道题,我就挑两道比较典型的题写一下博客吧。

双指针法的核心思路是通过合理的安排,减少暴力枚举的次数,争取在常数复杂度内解决问题。


15. 三数之和

题干

难度:中等

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

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

示例 1:

输入: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] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

题解

在哈希表那一章我们写了两数之和,当时要求是a+b=target,这道题很自然就想到固定abc之一,让a+b=-c,转化为两数之和问题,这样可以在常熟复杂度内解决。但是需要去重。

这是哈希表的核心代码,不再给出输入输出部分:

class Solution {
public:std::vector<std::vector<int>> threeSum(std::vector<int>& nums) {std::sort(nums.begin(), nums.end());std::vector<std::vector<int>> ans;for (int i = 0; i < nums.size(); i++) {if (i > 0 && nums[i] == nums[i - 1]) continue; // 跳过重复的istd::unordered_set<int> seen;for (int j = i + 1; j < nums.size(); j++) {int complement = -nums[i] - nums[j];if (seen.count(complement)) {ans.push_back({ nums[i], complement, nums[j] });while (j + 1 < nums.size() && nums[j] == nums[j+1]) j++; // 跳过重复的j}seen.insert(nums[j]);}}return ans;}
};

这种方法也能通过测试,只是效率略低,问题在于find过程中,每个数仍然被扫描了多次,没有真正意义上实现常数阶复杂度。

以下是完整的双指针法,确保每个数只会被扫过一次。

class Solution {
public:std::vector<std::vector<int>> threeSum(std::vector<int>& nums) {std::vector<std::vector<int>> ans;std::sort(nums.begin(), nums.end());for (int i = 0;i < nums.size();++i) {if (i > 0 && nums[i] == nums[i - 1])continue;int k = nums.size() - 1;for (int j = i + 1;j < nums.size();++j) {if (j > i + 1 && nums[j] == nums[j - 1]) continue;while (j < k && nums[i] + nums[j] + nums[k] > 0) k--;if (k == j) break;if (nums[i] + nums[j] + nums[k] == 0) ans.push_back({ nums[i],nums[j],nums[k] });}}return ans;}
};

知识点总结

  • 双指针法和单调性紧密相关,利用排序保证单调性。
  • 再次总结哈希表stl家族:unordered_map unordered_multimap unordered_set unordered_multiset 对应键唯一/允许键重复的桶结构,还有值唯一/允许值重复的集合结构。
  • 插入哈希表方法:insert和emplace。
  • 插入顺序容器方法:insert,push_back,emplace_back。
  • 现代c++统一初始化:利用{},实现变量、函数、类、容器等等几乎所有场景的初始化。
  • 初始化列表(initializer_list):利用{},创建initializer_list模板类。几乎所有的stl都提供了利用initializer_list的构造函数。

42. 接雨水

题干

难度:困难

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

img

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

题解

我的第一道困难题,其实也不是非常困难,可能因为之前在洛谷写过类似的题的缘故。之前做过一些双指针法-单调栈/单调队列的问题。直接给出代码吧。

class Solution {
public:int trap(std::vector<int>& height) {int l = 0, r = height.size() - 1, maxH = 0, sumArea = 0, blockArea = 0;for (int i : height) {maxH = std::max(maxH, i);blockArea += i;}for (int h = 1;h <= maxH;++h) {while (height[l] < h) l++;while (height[r] < h) r--;sumArea += (r - l + 1);}return sumArea - blockArea;}
};

非常简单,但是足够解决问题了,方法就是先计算总面积,再减去柱子面积,即可得到水的面积。总面积通过双指针可得。

其实没什么好说的,这道题同样有单调栈解法,不过我没有写,可以看一下洛谷的单调栈问题:P1950 长方形 - 洛谷。

另外洛谷的[P2866 USACO06NOV] Bad Hair Day S - 洛谷这道题和本题核心高度一致。

http://www.xdnf.cn/news/247789.html

相关文章:

  • 基于DrissionPage的高效爬虫开发:以小说网站数据抓取为例
  • vue自定义表头内容excel表格导出
  • LangChain4j +DeepSeek大模型应用开发——7 项目实战 创建硅谷小鹿
  • SpringAI使用OpenAI API格式调用DeepSeek服务
  • 《AIStarter安装部署全攻略:AI绘画/数字人项目快速上手指南(含Windows环境配置要点)》
  • *(解引用运算符)与 ++(自增运算符)的优先级
  • 开始一个vue项目
  • 《排序算法总结》
  • 60常用控件_QSpinBox的使用
  • [FPGA Video IP] Frame Buffer Read and Write
  • 一文读懂EMC VNX存储的Fast Cache(第二部分:对比)
  • 【RocketMQ】- 源码系列目录
  • 实习入职的总结
  • 前端八股 CSS 1
  • Chromium 134 编译指南 - Android 篇:从Linux版切换到Android版(六)
  • 2025智能体的发展趋势
  • 深⼊理解指针(8)
  • 简单的Qwen3的本地部署、分析与常见报错
  • Cribl 数据脱敏 更多方法 MASK (三)
  • 第十六届 -- 蓝桥杯Web开发大学组省赛个人复盘
  • ESP-ADF esp_dispatcher组件之audio_service子模块资源管理函数详解
  • RAGFlow上传3M是excel表格到知识库,提示上传的文件总大小过大
  • 基于Redis实现-附近商铺查询
  • UE实用地编插件Physical Layout Tool
  • MySQL | DQL语句-连接查询
  • linux 使用nginx部署next.js项目,并使用pm2守护进程
  • 加载ko驱动模块:显示Arm版本问题解决!
  • 小白如何入门Python爬虫
  • 【playwright】内网离线部署playwright
  • PMP-第九章 项目资源管理(一)