ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LeetCode-Go 题解:859. Buddy Strings(亲密字符串)——两种情况的分类讨论与 Go 实现

2026/9/12 1:20:55 拓冰建站 浏览量
LeetCode-Go 题解:859. Buddy Strings(亲密字符串)——两种情况的分类讨论与 Go 实现 LeetCode-Go 题解859. Buddy Strings亲密字符串——两种情况的分类讨论与 Go 实现【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go导读本文以 leetcode/0859.Buddy-Strings/README.md 为骨架完整解析 LeetCode 第 859 题 Buddy Strings亲密字符串的题意、分类讨论思路与 Go 实现。题目要求判断能否通过恰好交换一次字符串 s 中的两个字符使其与 goal 相等。读完本文你将掌握该题的两种核心情形判定两字符串相等与两字符串不等、单次线性扫描的 O(n) 解法以及仓库中配套单测对边界条件的覆盖方式并可直接基于仓库源码运行验证。题目描述给定两个字符串s和goal如果可以通过交换s中的两个字母得到与goal相等的结果则返回true否则返回false。交换字母的定义为取两个下标i和j下标从 0 开始且满足i ! j接着交换s[i]和s[j]处的字符。例如在abcd中交换下标 0 和下标 2 的字符可以得到cbad。题目给出的四个示例输入输出说明s ab,goal batrue交换s[0] a与s[1] b得到ba与 goal 相等s ab,goal abfalse唯一可交换的是s[0]与s[1]交换后得到ba不等于 goals aa,goal aatrue交换s[0] a与s[1] a后仍为aa与 goal 相等s aaaaaaabc,goal aaaaaaacbtrue交换倒数第二位与最后一位即可题目约束1 s.length, goal.length 2 * 10000s和goal仅由小写字母组成说明本题的题意要点是恰好交换一次且必须真实执行一次交换操作这与两串相等即可的直觉判断存在关键差异也是第 2 个示例abvsab返回false之所以成立的原因。解题思路按两种情形分类讨论从 README 的解题思路出发问题可以拆分为两个互斥的大分支情形一s goal判断 s 中是否存在重复字符当两个字符串完全相等时要满足交换一次后仍等于 goal唯一可能是交换的两个字符完全相同交换后字符串不变。因此若s中存在重复字符至少有一个字符出现次数 ≥ 2则可以交换该字符出现的两个位置字符串保持不变返回true若s中所有字符互不相同如ab则任何一次真实交换都会改变字符串返回false。这就是 README 中s等于goals中有重复元素就返回true否则返回false的完整含义。情形二s ! goal统计两串的错位位置当两个字符串不相等时要能通过一次交换变相等必须满足以下全部条件两串长度相等否则根本无法交换对齐错位位置恰好有且仅有 2 个多于 2 个说明一次交换解决不了少于 2 个则与s ! goal矛盾这 2 个错位位置呈交叉相等关系s[first] goal[second]且s[second] goal[first]即交换s中这两个位置的字符后正好能对齐goal。这正是 README 中s不等于goals中有两个下标不同的字符与goal中对应下标的字符分别相等的展开解释。代码实现与逐行解读核心实现位于 859.Buddy Strings.go完整代码如下package leetcode func buddyStrings(s string, goal string) bool { if len(s) ! len(goal) || len(s) 1 { return false } mp : make(map[byte]int) if s goal { for i : 0; i len(s); i { if _, ok : mp[s[i]]; ok { return true } mp[s[i]] } return false } first, second : -1, -1 for i : 0; i len(s); i { if s[i] ! goal[i] { if first -1 { first i } else if second -1 { second i } else { return false } } } return second ! -1 s[first] goal[second] s[second] goal[first] }逐段解读如下1. 前置过滤第 46 行if len(s) ! len(goal) || len(s) 1 { return false }两串长度不等无法通过一次交换使它们相等直接返回false长度 ≤ 1 时不存在两个不同下标可供交换题目要求i ! j返回false。测试用例中{a, a}期望结果为false正是验证这一点。2. 情形一s goal第 716 行mp : make(map[byte]int) if s goal { for i : 0; i len(s); i { if _, ok : mp[s[i]]; ok { return true } mp[s[i]] } return false }利用哈希表mp记录已出现的字符线性扫描过程中一旦发现某个字符第二次出现说明存在可交换的重复字符对立即返回true扫描结束仍无重复返回false。3. 情形二s ! goal第 1729 行first, second : -1, -1 for i : 0; i len(s); i { if s[i] ! goal[i] { if first -1 { first i } else if second -1 { second i } else { return false } } } return second ! -1 s[first] goal[second] s[second] goal[first]first、second记录前两个错位下标初始为-1表示尚未找到单次扫描收集错位位置找到第 3 个错位位置时说明一次交换无法解决立即返回false循环结束后second ! -1保证错位恰好为 2 个再检查交叉相等关系s[first] goal[second] s[second] goal[first]两者同时成立才返回true。复杂度分析时间复杂度O(n)其中 n 为字符串长度。两个分支各自只需一次线性扫描空间复杂度O(1)。由于题目约束s、goal仅含小写字母mp中最多容纳 26 个键可视为常数级空间若不考虑该约束上限为 O(n)。测试用例验证从仓库单测看边界覆盖仓库配套单测位于 859.Buddy Strings_test.go除了题目给出的 4 个示例ab/ba、ab/ab、aa/aa、aaaaaaabc/aaaaaaacb均返回true或false与题目一致还补充了 3 个重要的边界用例输入期望输出覆盖点{ab, abc}false两串长度不等触发前置过滤{a, a}false长度 ≤ 1无下标对可供交换{abcd, badc}false错位位置超过 2 个4 处一次交换无法修复其中{abcd, badc}是对错位多于 2 个直接返回false分支源码第 2225 行的直接验证{a, a}验证了长度小于等于 1 直接返回false的前置判断。所有用例均与源码行为一致体现了仓库100% test coverage的测试组织方式——测试文件采用question859/para859/ans859结构体组织输入输出对并在Test_Problem859中循环断言。运行与验证方式本仓库的 LeetCode 题解按题号组织在 leetcode 目录下每个题目一个子目录包含题号.题名.go解法、题号.题名_test.go测试与README.md题目与思路说明。若要在本地验证本题解法可在仓库根目录下执行 Go 测试命令go test -v -run Test_Problem859 ./leetcode/0859.Buddy-Strings/执行后将输出题目编号标识与每组输入对应的buddyStrings结果可与 859.Buddy Strings_test.go 中的期望值逐一比对。小结LeetCode 859 Buddy Strings 是一道典型的分类讨论题核心在于厘清恰好交换一次这一限定条件两串相等时问的是是否存在可交换的相同字符对即是否存在重复字符两串不等时问的是错位是否恰好两处且可交叉互换对齐。仓库给出的 Go 解法以两次线性扫描分别覆盖这两种情形时间复杂度 O(n)、空间复杂度 O(1)配合单测完整覆盖了长度不等、长度过短、多错位等边界情况代码简洁且可直接复用。【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考