LogicStack-LeetCode 刷穿系列:LeetCode 519 随机翻转矩阵——哈希表映射与双指针两种解法详解
教程文档【免费下载链接】LogicStack-LeetCode公众号「宫水三叶的刷题日记」刷穿 LeetCode 系列文章源码项目地址https://gitcode.com/gh_mirrors/lo/LogicStack-LeetCode点击查看免费下载本篇技术指南以 LeetCode 519. 随机翻转矩阵 的题解为主体完整拆解「等概率随机选取矩阵中未被翻转的格子」这一经典无放回抽样问题。读者将掌握如何利用坐标编号把二维矩阵压缩为一维区间、如何在翻转操作导致区间断裂后仍保持单次随机与等概率以及「双指针扫描」与「哈希表 swap 映射」两种解法的原理、代码与复杂度边界并顺带理解其与 380、710 等同源题的通用套路。题目描述与核心难点给定一个m x n的二元矩阵matrix所有值初始化为0。需要实现一个Solution类支持Solution(int m, int n)按矩阵大小m、n初始化对象int[] flip()等概率随机返回一个满足matrix[i][j] 0的下标[i, j]并将其值变为1void reset()将矩阵中所有值重置为0。题目的附加要求是尽量最少调用内置随机函数并优化时间与空间复杂度。数据约束为1 m, n 10^4flip与reset最多被调用1000次且每次调用flip时矩阵中至少存在一个0。本题目有三个关键难点矩阵规模过大m, n最大可达10^4矩阵最多有10^8个格子无法真实构建二维数组也无法用标记数组记录每个格子是否被翻转过。无放回等概率每次flip都相当于从剩余为0的格子中做一次无放回随机抽取必须保证每个剩余格子被选中的概率均等。随机调用次数要少拒绝采样随机到一个已经被翻转的位置就重新随机在翻转次数接近总格子数时会被大量拒绝随机调用次数无法保证。核心思路二维坐标压缩为一维编号一个关键观察是二维坐标(i, j)与编号存在一一对应关系idx row * n col反过来给定编号idx可以还原出坐标row idx / n col idx % n这样一来问题就从「在m x n的二维矩阵中随机选未翻转格子」等价转换为「在[0, m * n)的一维区间中随机选一个未被使用的编号」。这正是整个题解的出发点二维问题的维度压缩。下文两种解法都在这个一维编号体系上展开。解法一双指针向两侧扫描借用「双指针」思想原始文档将该解法标记为「双指针」其思路是利用翻转总次数只有1000次数据范围10^3在[0, m * n)范围内随机出一个下标idx然后用两个指针分别从idx向左a和向右b扫描找到最近一个未被使用的位置将其标记翻转并返回。该做法相比「拒绝采样」的优势在于单次flip操作中只会调用一次随机方法。同时因为矩阵中最多只有1000个位置被翻转从随机点向两侧的扫描距离被已翻转位置数所限制复杂度具有保证。Java 参考实现来自原题解class Solution { int m, n; SetInteger set new HashSet(); Random random new Random(300); public Solution(int _m, int _n) { m _m; n _n; } public int[] flip() { int a random.nextInt(m * n), b a; while (a 0 set.contains(a)) a--; while (b m * n set.contains(b)) b; int c a 0 !set.contains(a) ? a : b; set.add(c); return new int[]{c / n, c % n}; } public void reset() { set.clear(); } }代码要点解析SetInteger set记录所有已被翻转的编号即值为1的格子不需要真实构建m * n的矩阵random.nextInt(m * n)在[0, m * n)内均匀随机一个编号a指针b从同一位置出发左侧指针a向左递减、右侧指针b向右递增跳过所有已在set中的编号最终优先取左侧找到的可用位置a否则取右侧的ba 0 !set.contains(a)的判断确保了选中的编号确实未被使用返回时将编号还原为坐标{c / n, c % n}reset只需清空set即可将所有格子重置为0。时间复杂度与空间复杂度令最大调用次数C 1000矩阵中最多有C个位置被翻转flip操作最坏复杂度为O(C)向两侧扫描经过所有已翻转位置reset复杂度为O(C)空间复杂度为O(C)用于存储set。解法二哈希表 swap随机区间始终连续解法一虽然在数据范围内可行但每次flip可能扫描多个已翻转位置最坏退化为O(C)。原始文档给出的更优做法是「哈希表 swap」核心目标是即使部分位置被翻转随机区间仍然保持连续每次仍能在[0, cnt)连续段内随机且单次flip严格O(1)。映射规则的设计起始时所有位置均未被翻转。规定未被翻转的位置其映射值为编号本身idx row * n col。由于未被翻转部分具有等值映射关系无需在哈希表中真实存储只记录被打破等值关系的映射。当随机到某个位置idx时分两种情况讨论原始文档的完整逻辑该位置未被哈希表真实记录未被翻转说明idx可被直接使用将idx作为本次随机点返回。同时把当前右端点尚未被使用位置的编号的映射值放到idx位置并将右端点左移一位。这样下次再随机到idx仍能直接取到idx的映射值随机区间的连续性得以维护该位置已被哈希表真实记录已被翻转此时idx里存的是上一次交换时的右端点映射值直接使用它即可然后用新的右端点映射值将其覆盖并更新右端点。同样保证了下次随机到idx时仍能直接取到有效映射。为什么这样能保证等概率整个算法的精髓在于[0, cnt)区间内每个位置始终对应一个尚未被使用的真实编号且这种对应是双射。每次flip相当于在[0, cnt)内均匀随机一个下标x取出x映射到的真实编号idx未被翻转过的位置映射值即自身将idx标记为已使用——具体做法是把区间最右端位置cnt - 1的映射值搬移到x上然后区间右端点左移cnt--。这正是经典数组尾部元素交换删除的哈希表版本因为每次都从尾部取一个未使用的编号来填补被随机走的位置所以区间[0, cnt)中的每个位置始终对应一个真实可用的格子随机范围随cnt同步收缩每个剩余格子被选中的概率自然均等。完整代码class Solution { int m, n, cnt; // cnt 为剩余数个数同时 cnt - 1 为区间右端点位置 MapInteger, Integer map new HashMap(); Random random new Random(300); public Solution(int _m, int _n) { m _m; n _n; cnt m * n; } public int[] flip() { int x random.nextInt(cnt--); int idx map.getOrDefault(x, x); map.put(x, map.getOrDefault(cnt, cnt)); return new int[]{idx / n, idx % n}; } public void reset() { cnt m * n; map.clear(); } }逐行解读这段非常精简的代码cnt m * n记录剩余可用格子数同时cnt - 1就是当前随机区间的右端点random.nextInt(cnt--)先在[0, cnt)内随机一个下标x随即cnt减一等价于先把右端点位置cnt - 1纳入可交换池再收缩区间map.getOrDefault(x, x)取出x的真实映射若x从未被记录未被翻转映射值即自身xmap.put(x, map.getOrDefault(cnt, cnt))将右端点位置cnt收缩后的新右端点的映射值写到x上——若cnt未被记录其映射值即cnt自身。这一步完成了用尾部可用编号填补被随机走的位置的交换返回{idx / n, idx % n}将真实编号还原为二维坐标reset恢复cnt并清空map。复杂度分析flip操作中只有一次nextInt和常数次哈希表读写时间复杂度为O(1)reset需要清空哈希表复杂度为O(C)空间复杂度为O(C)C 1000为最大翻转次数哈希表最多记录C个映射。一个直观的模拟示例以原题示例m 3, n 1共3个格子编号0, 1, 2为例首次flipcnt 3随机x假设x 1idx 1将cnt收缩为2并把编号2的映射写入位置1。返回[1, 0]第二次flipcnt 2在0, 2)内随机。若又随机到x 1此时map.getOrDefault(1, 1)取出的是上次写入的映射值2即返回尚未使用的格子2同时用当前右端点cnt 1覆盖位置1的映射第三次flipcnt 1只能随机到x 0对应编号0。可见无论随机序列如何返回的编号始终是尚未翻转过的格子且每个剩余格子被选中的概率始终均等。两种解法的对比与选型建议维度双指针扫描哈希表 swap单次随机调用次数1 次1 次flip时间复杂度最坏O(C)向两侧扫描严格O(1)reset时间复杂度O(C)O(C)空间复杂度O(C)SetO(C)Map核心思想就近填补尾部交换填补维护区间连续适用场景翻转次数少的题设C 1000翻转次数大、追求单次严格O(1)两者都保证了单次flip只调用一次随机函数都优于朴素拒绝采样。区别在于双指针解法借助总翻转次数少的题设用扫描换实现简单哈希表 swap 解法通过映射维护随机区间的连续性把flip降到严格O(1)在翻转次数接近矩阵大小时依然不会出现性能退化。实际面试与工程场景中哈希表 swap 是更通用的答案。同源题扩展从 380 到 710 的「映射 交换」套路「哈希表 swap 维持连续随机区间」并非 519 题独有在仓库的刷穿系列中是一个可复用的通用范式[380. O(1) 时间插入、删除和获取随机元素%20时间插入、删除和获取随机元素中等.md)用哈希表记录值 - 数组下标删除时将末尾元素搬到被删位置确保[0, idx]区间内都是存活值getRandom直接在连续区间内随机。这与 519 题解法二的尾部交换思想完全同源黑名单中的随机数从[0, n)中排除黑名单后随机。解法二将[0, n - m)内被禁用的数映射到[n - m, n)内可选的数上用两个Set区分范围、用Map记录映射把带黑名单的随机转化为连续区间内的随机同样体现了区间压缩 哈希映射的套路。三者放在一起可以看到一条清晰的进阶路径先用双指针/拒绝采样保证正确性再用哈希表 交换把随机区间压缩为连续段实现严格的O(1)随机。此外本仓库的 Index/哈希表.md 与 Index/双指针.md 将 519 题分别收录进「哈希表」和「双指针」两个 Tag 索引中读者可按标签体系系统检索同类题目。小结LeetCode 519「随机翻转矩阵」考察的是无放回等概率抽样在受限空间下的实现。本仓库题解给出的两条主线值得牢记二维转一维idx row * n col的编号映射把矩阵问题规约为一维区间问题连续区间维护用「双指针就近填补」或「哈希表 尾部交换」两种手段在部分元素被移除后依然保证随机区间的连续性从而做到单次随机调用与均等概率。其中解法二「哈希表 swap」在时间和空间上均达到最优且与 380、710 等题目共享同一套思维模型是随机化 哈希表类问题中值得反复练习的模板级解法。赞分享教程文档【免费下载链接】LogicStack-LeetCode公众号「宫水三叶的刷题日记」刷穿 LeetCode 系列文章源码项目地址https://gitcode.com/gh_mirrors/lo/LogicStack-LeetCode点击查看免费下载相关推荐LogicStack-LeetCode 刷穿 LeetCode 第 13 题罗马数字转整数模拟与哈希表双解法详解LogicStack LeetCode 刷穿 LeetCode 第 13 题罗马数字转整数模拟与哈希表双解法详解 本篇技术指南基于仓库 LogicStac教程文档LogicStack-LeetCode 题解精读LeetCode 138「复制带随机指针的链表」——哈希表映射与原地 O(1) 空间两种深拷贝方案LogicStack LeetCode 题解精读LeetCode 138「复制带随机指针的链表」——哈希表映射与原地 O 1 空间两种深拷贝方案 本篇文章基于教程文档AlgoNote 题解LeetCode 0519 随机翻转矩阵哈希表 映射交换实现等概率不重复随机AlgoNote 题解LeetCode 0519 随机翻转矩阵哈希表 映射交换实现等概率不重复随机 导读 本篇基于《算法通关手册》AlgoNote教程文档知识库上一篇EmbedAI安全特性深度剖析为什么你的数据永远不会离开本地环境下一篇simplewall静默安装方法企业部署实用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Meteor 模块运行时 modules-runtime 深度解析:meteorInstall 的构造、解析规则与错误防护机制

Meteor 模块运行时 modules-runtime 深度解析:meteorInstall 的构造、解析规则与错误防护机制

后端前端开发工具移动开发 【免费下载链接】meteor Meteor, the JavaScript App Platform 项目地址: https://gitcode.com/gh_mirrors/me/meteor 点击查看 免费下载 packages/modules-runtime 是 Meteor 应用平台中负责实现 CommonJS 模块加载的运行时内核包。它对…

2026/10/10 1:48:45 阅读更多 →
impeccable:从代码质量到设计系统,如何构建无懈可击的交付标准

impeccable:从代码质量到设计系统,如何构建无懈可击的交付标准

1. 一个词撬动整套做事标准:impeccable 到底在说什么第一次看到“impeccable”这个词,是在一份英文设计评审意见里。对方只写了一句话:“The spacing is not impeccable.” 没有具体指出哪里不对,但整个团队立刻明白——这不是“有…

2026/10/10 1:48:45 阅读更多 →
Uber Go Style Guide 性能篇:热路径上必守的三条 Go 性能优化准则

Uber Go Style Guide 性能篇:热路径上必守的三条 Go 性能优化准则

文档教程代码质量Lint 【免费下载链接】guide The Uber Go Style Guide. 项目地址: https://gitcode.com/gh_mirrors/gu/guide 点击查看 免费下载 导读:本文整理自 Uber Go Style Guide 仓库(src/performance.md)的 Performance …

2026/10/10 1:48:45 阅读更多 →

最新新闻

impeccable:一款面向OpenAPI契约的Python自动化校验工具

impeccable:一款面向OpenAPI契约的Python自动化校验工具

我无法基于当前输入生成符合要求的博文。原因如下:输入中仅提供了项目标题"impeccable",以及空置的“相关热搜词”“最新网络热词”和完全空白的搜索内容块(),未提供任何实质性的项目正文、关键词列表或摘要…

2026/10/10 21:47:36 阅读更多 →
X射线底片焊缝缺陷检测:2647张6类标注数据集,可直接喂给YOLO

X射线底片焊缝缺陷检测:2647张6类标注数据集,可直接喂给YOLO

简介:面向工业X射线底片焊缝缺陷检测的目标检测数据集,涵盖裂纹、未熔合、未渗透等6类焊缝缺陷,共2647张底片图像、4766个真实标注框,适合用于YOLO、Faster R-CNN等目标检测模型的训练与评测。数据采用VOC与YOLO双格式存储&#x…

2026/10/10 21:47:36 阅读更多 →
AI辅助软件测试实战:从脚本生成到日志分析的全流程经验

AI辅助软件测试实战:从脚本生成到日志分析的全流程经验

软件测试这行的工具形态,这几年变化比我入行前十年加起来都大。以前同行碰头聊提效,无非是自动化框架怎么搭、脚本怎么写更稳、CI怎么接;现在问得最多的变成了"你平时用哪个AI工具""Prompt怎么写的""AI生成的脚本你…

2026/10/10 21:47:36 阅读更多 →
开源AI测试工具落地指南:从接口自动化到自愈定位器的实践选型

开源AI测试工具落地指南:从接口自动化到自愈定位器的实践选型

软件测试这个岗位,这两年的变化比过去十年加起来都大。我记得年初帮一个测试组做评审,同事把一份AI生成的接口用例贴出来,从覆盖路径到断言写法看着都像模像样,但一跑就发现大量断言是“凭空捏造”的——它把响应里根本不存在的字…

2026/10/10 21:47:36 阅读更多 →
Inno Setup自定义安装界面:ILSpy反编译+WinForms回调实践

Inno Setup自定义安装界面:ILSpy反编译+WinForms回调实践

简介:一套面向.NET应用开发者的Inno Setup自定义安装界面资源,用于解决安装包界面模板固化、动态配置繁琐的问题。资源基于Inno Setup增强版封装,内置对.NET Framework 4的依赖支持,并将界面逻辑集中在Code.iss脚本中,…

2026/10/10 21:47:36 阅读更多 →
【Claude Code】BMad-Method 多智能体协作实战:PRD 与架构文档一键生成,TaoToken 统一 Key 接入

【Claude Code】BMad-Method 多智能体协作实战:PRD 与架构文档一键生成,TaoToken 统一 Key 接入

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 21:46:35 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →