LeetCode 1980 Find Unique Binary String 全解:回溯、Cantor 对角线、随机化与 Trie 五种思路及多语言实现

发布时间:2026/9/17 20:40:35

LeetCode 1980 Find Unique Binary String 全解:回溯、Cantor 对角线、随机化与 Trie 五种思路及多语言实现 LeetCode 1980 Find Unique Binary String 全解回溯、Cantor 对角线、随机化与 Trie 五种思路及多语言实现【免费下载链接】leetcodeLeetcode solutions项目地址: https://gitcode.com/GitHub_Trending/leetcode1/leetcode本文以 articles/find-unique-binary-string.md 为骨架系统讲解 LeetCode 1980「Find Unique Binary String」这道经典题的五种解法递归回溯、迭代回溯、Cantor 对角线构造、随机化与 Trie 前缀树。读者学完将掌握「在 2^n 个二进制串中高效找出缺失串」的证明思路与编码技巧并可在 Python、Java、C、Kotlin 等仓库多语言实现中直接对照验证。前置知识动手解题前建议先具备以下基础能力Hash Set利用集合的 O(1) 查找判断某个字符串是否已存在回溯 / 递归逐字符构造解空间并探索所有可能性二进制串处理整数与二进制字符串之间的互相转换、补零操作Cantor 对角线论证可选一种数学证明技术能保证构造出「与集合中每个元素都不同」的新元素是本体的最优解的理论根基。问题本质为什么缺失串一定存在给定一个长度为n的二进制字符串数组nums共n个串每个串长度也是n要求返回任意一个不在nums中出现过的长度为n的二进制串。关键洞察在于鸽巢原理长度为n的二进制串一共有2^n种而输入只有n个因此当n ≥ 1时必然2^n n缺失串一定存在。这一事实是所有解法尤其是随机化的正确性的前提。解法一回溯递归思路既然缺失串必然存在我们只需按字典序或任意顺序系统地构造候选串逐一检查是否出现在集合中。递归回溯从「全 0」串出发逐位尝试0与1第一个不在集合中的完整串即为答案。算法步骤将nums全部存入哈希集合获得 O(1) 查询从全0字符串开始递归在第i位若i n判断当前串是否在集合中不在则返回先保持第i位为0递归若失败将第i位改为1再递归返回第一个不在集合中的串。Python 实现class Solution: def findDifferentBinaryString(self, nums: List[str]) - str: strSet {s for s in nums} def backtrack(i, cur): if i len(nums): res .join(cur) return None if res in strSet else res res backtrack(i 1, cur) if res: return res cur[i] 1 return backtrack(i 1, cur) return backtrack(0, [0 for _ in nums])仓库源码对照仓库中 python/1980-find-unique-binary-string.py 与该实现完全一致且在每次失败分支后都显式检查并返回逻辑等价。其他语言版本同样遵循「先试 0 再试 1」的骨架java/1980-find-unique-binary-string.java 使用Set.of(nums)构建不可变集合并用StringBuffer递归kotlin/1980-find-unique-binary-string.kt 用CharArray与内联递归函数backtrack返回Boolean标志cpp/1980-find-unique-binary-string.cpp 则直接对0、1两个字符做 for 循环回溯push/pop并在成员变量result非空时提前剪枝返回。注意该 C 实现的时间复杂度注释为 O(2^N · N)遍历全部候选并拼接文档正文给出的递归版本因为「先试 0、失败才试 1」的贪心顺序实际只需访问少量节点均摊为 O(n²)。复杂度时间复杂度O(n²)空间复杂度O(n)递归栈 当前串解法二回溯迭代思路递归本质上是在隐式地遍历一棵二叉树。如果只想快速拿到一个答案可以直接遍历 0 到 n 的整数将其转换为定长二进制串后检查是否在集合中。因为只检查 n1 个候选而输入只有 n 个串必然能命中一个缺失串。算法步骤将nums存入哈希集合num从0遍历到n将num转成二进制串并用前导零补齐到长度n若不在集合中直接返回兜底返回空串理论上前 n1 个候选内必能找到。Python 实现class Solution: def findDifferentBinaryString(self, nums: List[str]) - str: strSet set(nums) n len(nums) for num in range(1 n): res bin(num)[2:].zfill(n) if res not in strSet: return res return 关键细节前导零补位各语言的补位手法各不相同这是本题最容易踩坑的地方Pythonbin(num)[2:].zfill(n)JavaString.format(% n s, Integer.toBinaryString(num)).replace( , 0)C自定义toBinaryString(int num, int length)逐位检查num (1 i)JavaScriptnum.toString(2).padStart(n, 0)Gofmt.Sprintf(%0*b, n, num)Rustformat!({:0width$b}, num, width n)。复杂度时间复杂度O(n²)空间复杂度O(n)解法三Cantor 对角线论证最优思路Cantor 对角线论证是本题最优雅、最快的解法时间复杂度 O(n)且完全不需要哈希集合。核心思想对每个输入串nums[i]取其第i个字符并翻转。构造出的串在第 0 位与nums[0]不同、在第 1 位与nums[1]不同……以此类推从而保证与每一个输入串至少在一位上不同。直觉上可以想象一个 n×n 的「字符串矩阵」我们沿着对角线取字符并全部取反得到的行必然与矩阵中的每一行都不同——这正是 Cantor 用来证明实数不可数的经典手法在本题的落地。算法步骤初始化空结果串对i从0到n-1读取对角线字符nums[i][i]追加其相反字符0变11变0返回结果串。Python 实现class Solution: def findDifferentBinaryString(self, nums: List[str]) - str: res [] for i in range(len(nums)): if nums[i][i] 0: res.append(1) else: res.append(0) return .join(res)验证示例以nums [01, 10]为例nums[0][0] 0→ 追加1nums[1][1] 0→ 追加1。结果11与01在第 0 位不同、与10在第 1 位不同确实不在输入中。复杂度时间复杂度O(n)空间复杂度O(1) 额外空间结果串本身 O(n)这是面试中最推荐的答案既无集合开销也无递归深度还附带一个漂亮的数学故事。解法四随机化思路利用「候选空间远大于输入规模」这一事实2^n个可能串中只有n个被占用随机生成一个串命中缺失串的概率至少为(2^n - n) / 2^n当n稍大时该概率趋近于 1。因此反复随机生成并查集合期望尝试次数非常小。算法步骤将nums存入哈希集合无限循环每位随机取0或1拼成长度为n的串若不在集合中则返回由于输入稀疏期望尝试次数极少。Python 实现class Solution: def findDifferentBinaryString(self, nums: List[str]) - str: strSet set(nums) n len(nums) while True: res .join(random.choice(01) for _ in range(n)) if res not in strSet: return res各语言随机源示例Java 用random.nextBoolean()、C 用rand() % 2、Go 用rand.Intn(2)、Rust 用rng.gen_bool(0.5)、Swift 用Bool.random()。复杂度时间复杂度最坏情况 O(∞)理论上有无限循环可能实际期望极快空间复杂度O(n)适用提示随机化解法代码最简但属于「概率性正确」面试讲解时应主动指出其期望复杂度与最坏情况体现严谨性。解法五Trie 前缀树思路用 Trie 存储所有输入串后从根节点出发寻找「断枝」若某节点缺少0或1子节点说明存在一条不经过任何已存串的路径沿该路径走下去并用任意字符补齐即可得到一个缺失串。算法步骤将所有输入串插入 Trie从根节点遍历若0子节点缺失追加0并返回剩余位置任意填充若1子节点缺失追加1并返回若两个子节点都存在优先走1继续深入若结果长度不足n用1补齐返回构造出的串。Python 实现class Node: def __init__(self): self.children [None, None] def contains_bit(self, bit: int) - bool: return self.children[bit] is not None def put(self, bit: int): self.children[bit] Node() def get(self, bit: int): return self.children[bit] class Trie: def __init__(self): self.root Node() def insert(self, s: str): curr self.root for c in s: bit int(c) if not curr.contains_bit(bit): curr.put(bit) curr curr.get(bit) def search(self, res: str, curr) - bool: while curr.contains_bit(0) or curr.contains_bit(1): if not curr.contains_bit(0): res.append(0) return True if not curr.contains_bit(1): res.append(1) return True res.append(1) curr curr.get(1) return False class Solution: def findDifferentBinaryString(self, nums: List[str]) - str: trie Trie() for s in nums: trie.insert(s) res [] trie.search(res, trie.root) while len(res) len(nums): res.append(1) return .join(res)原文档给出了 Node / Trie 拆分的完整多语言实现Java、C、JavaScript、C#、Go、Kotlin、Swift、Rust核心结构一致children[2]数组 containsBit / put / get三个方法Rust 版使用OptionBoxTrieNode表达可选子节点。复杂度时间复杂度O(n²)建树 O(n²)查找 O(n)空间复杂度O(n²)Trie 解法适合作为「数据结构选型」的展示当问题演化成需要多次查询或动态增删时前缀树结构能复用。常见陷阱陷阱一枚举全部 2^n 个候选虽然缺失串必然存在但直接遍历2^n个可能串是指数级开销n稍大就会超时。最优做法只需检查n1个候选解法二或直接使用 Cantor 对角线解法三。陷阱二忘记给二进制串补前导零整数转二进制后长度可能小于n例如n3时1应写成001而非1。忘记补零会导致生成的串长度错误无法与输入串正确比较。解法二的所有语言实现都显式做了补位请务必保留这一步。陷阱三误解 Cantor 对角线对角线法的精髓是翻转第 i 个串的第 i 个字符从而与每个串都在「自己那一行」不同。常见的错误是固定翻转某一位如总是翻转第一位这样只能保证与部分串不同无法覆盖全部输入。小结与仓库对照五种解法由「暴力」到「精巧」递进复杂度从 O(n²) 逐步收敛到 O(n)解法核心思路时间复杂度空间复杂度递归回溯逐位构造 集合去重O(n²)O(n)迭代回溯遍历 0..n 转定长二进制串O(n²)O(n)Cantor 对角线翻转对角线上每个字符O(n)O(1) 额外随机化概率命中缺失串期望极小O(n)Trie 前缀树沿缺失子节点构造O(n²)O(n²)本仓库围绕该题提供了可直接运行的完整实现Python、Java、C、Kotlin均以递归回溯为基线解法代码注释中标注了各自的复杂度分析适合作为刷题后的对照与复习材料。原文档 articles/find-unique-binary-string.md 还给出了其余语言JavaScript、C#、Go、Swift、Rust 等的完整 tab 实现可作为多语言横向对比的参考。【免费下载链接】leetcodeLeetcode solutions项目地址: https://gitcode.com/GitHub_Trending/leetcode1/leetcode创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/17 20:40:35

VSCode + CMake 构建配置指南:从环境搭建到工程实践

1. 为什么非要在 VSCode 里配一套 CMake先回答一个很多人纠结的问题:我本来是写单片机的,或者我一直在用某款 IDE 写 C/C,为什么要折腾 VSCode 和 CMake?我自己的感受是:VSCode 本身定位就是个「编辑器」,它…

2026/9/17 20:40:35

IDEA配置Tomcat全攻略:从版本选择到部署调试的完整指南

先把话放前面:这篇是给那些在 IDEA 里折腾 Tomcat 折腾到怀疑人生的人写的。不管你是刚学 Java Web 的新手,还是从 MyEclipse 转过来的老用户,只要你在 2023 版的 IntelliJ IDEA 里想把 Tomcat 跑起来,这篇文章就是照着做完就能跑…

2026/9/17 20:40:35

VS2022启动报错“无法找到一个或多个组件”?完整排查修复指南

我自己的电脑前两天就翻车了。早上到工位,像往常一样双击 VS2022,结果没进启动页,一个弹窗先拍在我脸上——“无法找到一个或多个组件”。我第一反应是项目文件坏了?换了个几个解决方案也一样。然后我打开 Visual Studio Installe…

2026/9/17 21:25:42

激光技术课件自动化:python-pptx、M²拟合与交付自检

简介:这份《专题一 激光技术.ppt》面向物理、光电信息、电子工程等专业的学生与初入激光领域的自学者,用于系统梳理激光原理与技术脉络。课件从爱因斯坦1916年提出受激辐射讲起,串联汤斯与肖洛的经典论文、梅曼的红宝石激光器、He-Ne气体激光…

2026/9/17 21:20:41

Agent技能体系实战:从碎片化工具到可复用技能包

近两年只要在搞大模型应用,基本绕不开一个词:Agent。而我在本地搭建并维护了一个叫agent-skills的项目之后,最大的感受是----大家平时聊 Agent 时都喜欢强调模型推理、记忆、规划,但真正让 Agent 从“聊天机器人”变成“能干活的人…

2026/9/16 12:52:37

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/17 0:03:13

WiFi密码安全测试:从原理到实战的字典暴力破解指南

1. 写在前面:我为什么要研究WiFi密码这件事先交代一下背景。我身边有不少朋友,家里的WiFi密码常年是"12345678"或者"88888888",问就是"好记"。直到有一次,隔壁邻居蹭网蹭到我家路由器后台都进不去&…

2026/9/17 0:03:13

redis-py服务控制与监控函数实战:从ping到slowlog的巡检指南

我用 redis-py 写了快五年的业务代码,坦白说,真正让我觉得这个客户端“像一个成熟工具箱”的,不是 get/set 那套基本操作,而是它那批专门做服务控制与状态监控的辅助函数。日常开发里,大家把redis.Redis(host..., deco…

2026/9/17 0:03:13

SpringBoot+Vue3实现中小企业设备管理系统开发实践

1. 项目概述与核心价值中小企业设备管理系统是制造业、服务业等领域的基础信息化工具。传统设备管理往往依赖Excel表格或纸质记录,存在数据孤岛、流程混乱、维护成本高等痛点。这套基于Java SpringBootVue3MyBatis的技术方案,通过前后端分离架构实现了设…

2026/9/16 22:55:57

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/16 22:56:09

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/16 22:56:16

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码