LeetCode-Go 题解精讲:1290. Convert Binary Number in a Linked List to Integer(链表二进制转十进制)
【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go
本篇文章围绕 LeetCode 第 1290 题「Convert Binary Number in a Linked List to Integer(链表中的二进制数转整数)」展开,以 leetcode/1290.Convert-Binary-Number-in-a-Linked-List-to-Integer/README.md 的官方题解为骨架,结合当前仓库中该题目的 Go 源码实现 与 单元测试,深入讲解「边遍历边累加」的迭代算法原理、复杂度分析、链表构造辅助工具,以及如何在本仓库环境下运行测试。读完本文,你将掌握链表与进制转换结合题目的通用解法,并能独立在仓库中定位、运行与验证本题代码。
一、题目回顾与题意拆解
题目原文(摘自关联文档):
Given
headwhich is a reference node to a singly-linked list. The value of each node in the linked list is either 0 or 1. The linked list holds the binary representation of a number. Return thedecimal valueof the number in the linked list.
即:给定单链表头结点head,链表中每个结点的值非 0 即 1,整条链表按从头到尾的顺序保存了一个整数的二进制表示,要求返回该二进制数对应的十进制值。
从仓库源码看,题目要求的ListNode结构在仓库中统一定义于 structures/ListNode.go:
// ListNode 是链接节点 type ListNode struct { Val int Next *ListNode }链表头部是二进制数的最高位(Most Significant Bit,MSB)。例如链表1 -> 0 -> 1表示二进制数(101)₂,其十进制值为 5。
示例数据速览
题目给出 5 组示例(均已在仓库测试中覆盖):
| 输入链表(头到尾) | 二进制含义 | 十进制输出 |
|---|---|---|
[1,0,1] | (101)₂ | 5 |
[0] | (0)₂ | 0 |
[1] | (1)₂ | 1 |
[1,0,0,1,0,0,1,1,1,0,0,0,0,0,0] | (100100111000000)₂ | 18880 |
[0,0] | (00)₂ | 0 |
约束条件
- 链表不为空(The Linked List is not empty)。
- 链表结点总数不超过 30(Number of nodes will not exceed
30)。 - 每个结点的值只能是
0或1(Each node's value is either0or1)。
结点数不超过 30,意味着最大表示的二进制数为 30 位,远在 32 位int的表示范围内(最大2³⁰ - 1),因此使用 Go 的int类型累加不会发生溢出,这也是可以直接用整数运算累加的前提。
二、解题思路:边遍历边累加(Horner 算法)
原文档给出的解题思路非常精炼:
给出一个链表,链表从头到尾表示的数是一个整数的二进制形式,要求输出这个整数的十进制。简单题,从头到尾遍历一次链表,边遍历边累加二进制位。
其核心思想是Horner 算法(秦九韶算法):从头结点(最高位)开始,每读入一个二进制位bit,就把当前累积值左移一位(乘 2)再加上该位,即:
sum = sum * 2 + bit以1 -> 0 -> 1为例模拟:
| 步骤 | 当前结点 | 累加过程 | sum |
|---|---|---|---|
| 1 | 1 | 0 * 2 + 1 | 1 |
| 2 | 0 | 1 * 2 + 0 | 2 |
| 3 | 1 | 2 * 2 + 1 | 5 |
最终得到 5,与(101)₂ = 1×2² + 0×2¹ + 1×2⁰ = 5完全一致。该过程本质上是在顺序遍历过程中完成了从高位到低位的位权展开,避免了先求链表长度再逐位乘位权的两次遍历。
三、仓库源码实现与逐行剖析
仓库中的实现位于 leetcode/1290.Convert-Binary-Number-in-a-Linked-List-to-Integer/1290. Convert Binary Number in a Linked List to Integer.go:
package leetcode import ( "github.com/halfrost/LeetCode-Go/structures" ) // ListNode define type ListNode = structures.ListNode // getDecimalValue 将二进制链表转换为十进制整数 func getDecimalValue(head *ListNode) int { sum := 0 for head != nil { sum = sum*2 + head.Val head = head.Next } return sum }逐行解读:
- 类型别名:
type ListNode = structures.ListNode把仓库统一数据结构包 structures/ListNode.go 中的ListNode引入到leetcode包中,保证各题共用同一份链表定义,避免重复造轮子。 - 初始化:
sum := 0作为十进制结果的累加器。 - 遍历循环:
for head != nil从头到尾遍历链表,循环内执行核心递推sum = sum*2 + head.Val。 - 指针推进:
head = head.Next移动到下一个结点,循环结束时所有二进制位均已处理。 - 返回结果:直接返回累加后的十进制整数。
该实现是典型的一次遍历 O(n) 解法,不依赖额外数据结构,空间开销为 O(1)。
两种等价写法对比
sum*2 + bit也可以写成位运算形式(sum << 1) | bit,两者在整数运算上完全等价。仓库选择了更直白、易读的算术写法,适合作为教学示例。若追求位运算风格,可写成:
func getDecimalValue(head *ListNode) int { sum := 0 for head != nil { sum = (sum << 1) | head.Val head = head.Next } return sum }由于二进制位只能是 0 或 1,(sum << 1) | bit与sum*2 + bit结果恒等,读者可以根据团队编码风格任选其一。
四、单元测试:题目五组用例全覆盖
仓库为本题配套了完整的表驱动测试,位于 leetcode/1290.Convert-Binary-Number-in-a-Linked-List-to-Integer/1290. Convert Binary Number in a Linked List to Integer_test.go:
type question1290 struct { para1290 ans1290 } // para 是参数 // one 代表第一个参数 type para1290 struct { one []int } // ans 是答案 // one 代表第一个答案 type ans1290 struct { one int } func Test_Problem1290(t *testing.T) { qs := []question1290{ { para1290{[]int{1, 0, 1}}, ans1290{5}, }, { para1290{[]int{0}}, ans1290{0}, }, { para1290{[]int{1}}, ans1290{1}, }, { para1290{[]int{0, 0}}, ans1290{0}, }, { para1290{[]int{1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0}}, ans1290{18880}, }, } fmt.Printf("------------------------Leetcode Problem 1290------------------------\n") for _, q := range qs { _, p := q.ans1290, q.para1290 fmt.Printf("【input】:%v 【output】:%v\n", p, getDecimalValue(structures.Ints2List(p.one))) } fmt.Printf("\n\n\n") }测试结构说明:
- 测试采用仓库统一的
questionXXX/paraXXX/ansXXX表驱动模式,para1290描述输入([]int切片),ans1290描述期望输出。 - 5 组用例与题目给出的 5 个示例一一对应,其中包含长度 15 的
[1,0,0,1,0,0,1,1,1,0,0,0,0,0,0] → 18880的较大规模用例,用于验证累积过程的正确性。 - 测试通过
structures.Ints2List(p.one)将整数切片转换为链表,再调用getDecimalValue,并打印输入输出便于人工核对。
测试用的链表构造工具
测试中使用的Ints2List与List2Ints定义于 structures/ListNode.go:
- Ints2List(nums []int) *ListNode:将整数切片按顺序构造成单链表(空切片返回
nil),测试输入用它把[1,0,1]变成1 -> 0 -> 1。 - List2Ints(head *ListNode) []int:反向把链表还原为切片,内部带 100 层深度限制,若链表过长或成环会直接 panic,避免测试死循环。
这两个工具是仓库大量链表题共用的基础设施,理解它们有助于阅读其他链表类题目的测试代码。
五、复杂度分析与边界情况
时间复杂度:O(n),其中 n 为链表结点数(题目约束 n ≤ 30)。算法仅需从头到尾单次遍历,每步只做一次乘加运算。
空间复杂度:O(1),只使用一个整型累加变量sum,不申请额外存储。
边界情况梳理(均已被测试覆盖):
- 单结点:
[0] → 0、[1] → 1,循环执行一次即返回,无需特殊处理。 - 全零链表:
[0,0] → 0,任何二进制位乘 2 累加后仍为 0。 - 前导零:如
[0,0]这类以 0 开头的链表,前导零不影响最终数值,算法天然兼容。 - 最长链表:30 位全 1 时结果最大为
2³⁰ - 1 = 1073741823,仍在int范围内,无溢出风险(这也是题目把结点数限制为 30 的原因)。
六、在本仓库中运行与验证
本项目根目录的 go.mod 声明模块名为github.com/halfrost/LeetCode-Go,并通过replace指令将structures等内部包指向本地目录,因此克隆仓库后无需额外下载内部依赖即可运行。
在仓库根目录执行以下命令,即可单独运行本题测试:
# 运行 1290 题专属测试(-v 输出详细日志) go test -v -run Test_Problem1290 ./leetcode/1290.Convert-Binary-Number-in-a-Linked-List-to-Integer/运行后会输出类似如下内容:
=== RUN Test_Problem1290 ------------------------Leetcode Problem 1290------------------------ 【input】:[1 0 1] 【output】:5 【input】:[0] 【output】:0 【input】:[1] 【output】:1 【input】:[0 0] 【output】:0 【input】:[1 0 0 1 0 0 1 1 1 0 0 0 0 0 0] 【output】:18880 --- PASS: Test_Problem1290 (0.00s) PASS ok github.com/halfrost/LeetCode-Go/leetcode/1290.Convert-Binary-Number-in-a-Linked-List-to-Integer 0.006s如需全量验证整个leetcode包,可执行:
go test ./leetcode/...仓库根目录还提供了 gotest.sh 脚本,用于一次性生成合法、单一的覆盖率文件coverage.txt:
./gotest.sh该脚本底层执行go test -covermode=atomic -coverprofile=coverage.txt ./leetcode/...,使用atomic覆盖模式,供 Codecov 等工具解析。题目的覆盖率结果可在仓库根目录的 coverage.txt 中查看(如github.com/halfrost/LeetCode-Go/leetcode/1290.Convert-Binary-Number-in-a-Linked-List-to-Integer相关条目)。
七、小结
本题是链表遍历与进制转换结合的基础题,仓库给出的解法仅 6 行核心逻辑,却同时体现了三个值得积累的要点:
- 方向感:链表头部是二进制最高位,必须从头到尾遍历,才能在不知道链表长度的情况下按「乘 2 进位」的方式逐位累加。
- 算法本质:
sum = sum*2 + bit是 Horner 求值法在二进制场景下的直接应用,一次遍历即可完成位权展开,无需预知链表长度或二次遍历。 - 工程配套:仓库通过 structures/ListNode.go 统一链表定义与构造/还原工具,配合表驱动测试与覆盖率脚本(gotest.sh),让每道题都能被低成本验证。
掌握这一「边遍历边累加」的范式后,遇到类似「链表表示数、要求求值」的题目(例如链表表示十进制大数、二进制求和等),都可以沿用同样的单次遍历累加思路快速求解。
【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考