资讯动态

Exercises 仓库实战:仓颉语言解 LeetCode「两数之和」——HashMap 一次遍历算法与仓颉语法要点

发布时间:2026/10/14 23:59:23 来源:尧图企业网站定制
示例工程教育【免费下载链接】Exercises本仓收集仓颉算法题解程序项目地址https://gitcode.com/Cangjie/Exercises点击查看免费下载本文基于 Exercises 仓库中 【Leetcode】1.两数之和 的题解文档展开完整讲解「两数之和」这道经典题目的 HashMap 一次遍历解法并结合 n1.cj 的真实源码深入剖析其中用到的仓颉语言Cangjie核心语法区间0..x、HashMap的基本使用、if-let枚举解构语法。读完本篇你既能掌握「空间换时间」的哈希解法思路也能获得一份可直接对照运行的仓颉语言实现范本。一、题目背景与仓库组织约定Exercises 是一个收集仓颉算法题解程序的仓库。根据仓库根目录 README.md 的提交要求每道编程题放在独立的子目录中目录以题目命名优先使用中文并在子目录下创建readme.md填写题目描述与解题指导。本篇的主角就是目录【Leetcode】1.两数之和/其内部仅有两个文件readme.md题目描述、解题思路、复杂度分析与涉及的仓颉语法清单n1.cj完整的仓颉题解源码。「两数之和」的题目描述为给定一个整数数组nums和一个整数目标值target在数组中找出和为目标值的那两个整数并返回它们的数组下标。通常附带两条假设每种输入只会对应一个答案且不能使用两次相同的元素答案可以按任意顺序返回。二、解题思路用 HashMap 把「查找」降为常数时间如果只用双重循环暴力枚举所有两两组合时间复杂度是 O(n²)。readme 中给出的核心思路是利用哈希表将查找操作均摊到 O(1)使用HashMap存放信息K数字本身V数字下标遍历数组每次用target - 当前数字得到一个数在 map 中查询是否存在这个 K如果查到返回当前数字的下标和查到的下标否则将当前数字作为 K当前下标作为 V放进 map 中。这里的关键洞察是遍历时把「已经走过的元素」记入哈希表于是「target - nums[i]是否存在」这个查找问题就从「在子数组中线性搜索」变成了「哈希表键值查询」。由于先查后存天然避免了「同一个元素被使用两次」的非法情况——查到互补值时那个值一定是之前下标的元素。readme 给出的复杂度结论时间 O(n)空间 O(n)。时间上每个元素最多入表一次、查表一次空间上哈希表最多保存 n 个键值对。三、仓颉实现逐行解析n1.cj下面是 n1.cj 的完整实现逐段说明package cangjieLeetcode.n1_n100 import std.collection.HashMap class SolutionN1 { func twoSum(nums: ArrayInt64, target: Int64): ArrayInt64 { let m HashMapInt64,Int64() let ans [-1,-1] for(i in 0..nums.size) { if (let Some(x) - m.get(target - nums[i])) { ans[0] i ans[1] x return ans } else { m.put(nums[i],i) } } ans } }逐点解析包与导入L18-L19package cangjieLeetcode.n1_n100将题解归类到 LeetCode 1~100 题的包命名空间import std.collection.HashMap从标准库引入哈希表类型这是实现该题唯一的外部依赖。函数签名L21func twoSum(nums: ArrayInt64, target: Int64): ArrayInt64。参数与返回值均使用 64 位整型Int64返回值为长度为 2 的下标数组与题目「返回两个下标」的要求一致。哈希表创建L22let m HashMapInt64,Int64()以类型参数声明键值均为Int64的哈希表恰好对应思路中的「K数字V下标」。注意仓颉中let声明的是不可变绑定绑定本身不可重新赋值但哈希表内部内容仍可通过方法修改。兜底返回值L23let ans [-1,-1]是题目保证有解时的占位结果若遍历结束仍未命中最后返回该数组L33 的表达式体即函数返回值起到防御性兜底作用。区间遍历L24for(i in 0..nums.size)使用仓颉的闭区间语法0..x右端点nums.size包含在内——这与部分语言中range(0, n)的左闭右开语义不同是本实现的一个易错点循环体共执行 n 次恰好覆盖下标 0 到 n-1。if-let 查询互补值L25-L29m.get(target - nums[i])的返回值是OptionInt64查到为Some(v)未查到为None。if (let Some(x) - ...)是仓颉对枚举的解构判断匹配成功时把值绑定到x并进入 if 分支失败则走 else 分支。这正是 readme 中强调的「if-let 判断枚举语法」。命中后ans[0] i; ans[1] x并立即return ans。入表L30m.put(nums[i], i)将当前数字与下标存入哈希表留给后续元素查找。四、涉及的仓颉语法清单结合本例展开readme 在「仓颉语法」一节列出了三个知识点它们恰好都体现在 n1.cj 中可以对照源码逐一消化1. 区间值0..x仓颉提供..区间构造语法0..nums.size产生一个包含两端点的整数区间可直接用于for-in循环。适用于一切需要按下标遍历定长数组的场景。阅读仓颉代码时要注意区分0..n含 n共 n1 个值本例中nums.size作为右端点被包含但循环体内用nums[i]访问数组实际用到的下标是 0 到 n-1逻辑正确。2. HashMap 的基本使用标准库std.collection提供的HashMapK, V支持操作本例写法说明创建HashMapInt64, Int64()泛型指定键、值类型写入m.put(nums[i], i)键不存在时插入存在时覆盖查询m.get(target - nums[i])返回OptionV需用模式匹配解包从源码结构看get返回Option而非裸值是仓颉以类型系统显式表达「可能不存在」的设计调用方必须处理None分支无法像某些语言那样「忘记判空」而不产生编译错误。3. if-let 判断枚举语法if (let Some(x) - expr)中-是模式匹配赋值等价于「若表达式结果为Some变体取其载荷绑定到 x条件为真」。它对None的分支由else承接。这一语法在仓颉中与Option、Result等代数类型配合替代了传统语言中的isSome()unwrap()两步写法使「查表 → 取用 → 兜底」的路径在单条语句中完成。五、复杂度验证与对照实验按 readme 的结论本实现时间复杂度 O(n)、空间复杂度 O(n)时间单层 for 循环执行 n 次每次的get/put均摊 O(1)无嵌套循环空间m最多存放 n 个键值对ans为 O(1) 额外数组。作为补充佐证仓库中 算法思想解题合集/src/leetcode/数据结构-哈希表.cj 收录了同一道题的另一版实现twoSumEqualToTargetSubscripts其思路与 n1.cj 完全一致但采用了更贴近仓颉集合惯用法的形式public func twoSumEqualToTargetSubscripts(nums: ArrayInt, target: Int): ?(Int, Int) { let indexForNum HashMapInt, Int() for ((index, value) in nums.iterator().enumerate()) { let remind target - value if (indexForNum.contains(remind)) { let ret (indexForNum[remind], index) return ret } else { indexForNum[value] index } } return None }两处值得对比的细节该版本用contains(key)先判断键存在性再通过下标语法indexForNum[remind]直接取值、indexForNum[value] index直接赋值与 n1.cj 中get/put的方法风格互为印证说明两种写法在标准库中均被支持返回值类型?(Int, Int)即Option(Int, Int)把「无解」显式建模为None比 n1.cj 的[-1, -1]占位更具类型表达力遍历方式使用nums.iterator().enumerate()解构出(index, value)元组避免了手写区间下标。该实现的正确性由同文件的verify()自检函数验证数据结构-哈希表.cjtwoSumEqualToTargetSubscripts([2, 7, 11, 15], 9).isSome()应得true对应下标 0、1 之和为 9twoSumEqualToTarget([2, 7, 11, 15], 9)同样返回true。这些verify()调用统一由 算法思想解题合集/src/main.cj 的testLeetCode()入口驱动运行整个 LeetCode 与剑指 Offer 题解的自校验流程。另外值得一提的是哈希解法的适用前提题目不保证数组有序。若数组有序可改用「左右双指针」在 O(1) 空间下完成仓库 算法思想解题合集/src/leetcode/思想-双指针.cj 收录了对应的有序数组版本首尾向中间逼近sum target时左指针右移否则右指针左移。选择哪种方案取决于输入是否有序这也是哈希解法值得 O(n) 空间的代价所在。六、运行与验证说明题解文件 n1.cj 声明package cangjieLeetcode.n1_n100依赖仅标准库std.collection.HashMap可使用仓颉编译器cjc直接编译编译运行环境以本机安装的仓颉工具链版本为准。同仓库的 算法思想解题合集 是完整的cjpm工程其 cjpm.toml 声明了cjc-version 0.57.3、output-type executable并依赖 gitcode 上的cjextensions与usablemacros两个外部包。在该子目录下按 cjpm 常规流程执行依赖安装与编译如cjpm build/cjpm test以当前 cjpm 工具版本实际支持的命令为准即可运行 main.cj 中的全部题解自检其中包括两数之和相关的验证用例。阅读仓库源码时建议的对照路径题目文档 readme.md → 题解实现 n1.cj → 同题变体与自检 数据结构-哈希表.cj → 统一测试入口 main.cj即可完整走通「思路 → 实现 → 验证」的闭环。七、小结本篇以 Exercises 仓库的第一道 LeetCode 题解为主线完整继承了 readme 中的思路四步法与 O(n)/O(n) 复杂度结论并落到 n1.cj 的逐行源码闭区间0..x控制遍历、HashMap的put/get完成「查-存」双动作、if-let解构Option消除显式判空。再配合 数据结构-哈希表.cj 中的第二版实现与可运行的verify()自检用例形成了一份从算法思想到仓颉语言实战、可验证、可复用的完整参考。掌握这一模式后「两数之和」类「在数组中找满足二元关系的元素」问题如三数之和、两数差、子集和变形都可沿用「已见元素入哈希表 当前元素查互补值」的模板进行推广。赞分享示例工程教育【免费下载链接】Exercises本仓收集仓颉算法题解程序项目地址https://gitcode.com/Cangjie/Exercises点击查看免费下载相关推荐《仓颉语言实战》仓颉Lambda表达式、闭包与管道语法糖函数高级用法完全指南《仓颉语言实战》仓颉Lambda表达式、闭包与管道语法糖函数高级用法完全指南 《仓颉语言实战》是张磊编著、清华大学出版社出版的仓颉语言入门教程本书示例代码库示例工程仓颉语言requests库技术文档仓颉语言requests库技术文档 1. 安装指南 版本选择 当前推荐使用v1.1.0版本v1.2.0存在已知问题 安装方式 该库为仓颉语言 Cangjie后端《仓颉语言实战》仓颉模式匹配深度指南match表达式的6种模式一次讲透《仓颉语言实战》仓颉模式匹配深度指南match表达式的6种模式一次讲透 仓颉模式匹配是仓颉语言中最具表达力的控制流特性之一。《仓颉语言实战》张磊著清华大学示例工程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑