当前位置: 首页 > news >正文

Leetcode 25

1 题目

1290. 二进制链表转整数

给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。

请你返回该链表所表示数字的 十进制值 。

最高位 在链表的头部。

示例 1:

输入:head = [1,0,1]
输出:5
解释:二进制数 (101) 转化为十进制数 (5)

示例 2:

输入:head = [0]
输出:0

提示:

  • 链表不为空。
  • 链表的结点总数不超过 30
  • 每个结点的值不是 0 就是 1

2 我写了错误的代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
int getDecimalValue(struct ListNode* head) {struct ListNode *cur = head;int result = 0 ;while (cur != NULL){int x = 0;result = result + cur->val * (2 ** (x));//本行开始报错x++;}return result;
}

你的思路方向是对的,但在 C 语言中不能直接使用2 **x这种幂运算语法,而且变量x的位置和递增方式也需要调整。下面是修改后的正确实现:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
int getDecimalValue(struct ListNode* head) {struct ListNode *cur = head;int length = 0;int result = 0;// 第一步:计算链表长度(确定最高位的幂)while (cur != NULL) {length++;cur = cur->next;}// 第二步:重新遍历链表计算十进制值cur = head;while (cur != NULL) {length--;  // 从最高位开始递减// 使用pow函数需要包含math.h,这里用移位运算更高效result += cur->val * (1 << length);cur = cur->next;}return result;
}

代码说明:

  1. 首先需要遍历一次链表获取长度,这样才能知道最高位是 2 的多少次方
  2. C 语言中计算 2 的幂可以用移位运算1 << n(相当于 2ⁿ),比使用pow()函数更高效
  3. 第二次遍历链表时,从最高位开始计算,每移动一个节点,幂次就减 1
  4. 累加每个节点值与对应权重的乘积,得到最终的十进制结果

例如对于链表1->0->1

  • 第一次遍历得到长度为 3
  • 第二次遍历:
    • 第一个节点:1 × 2² = 4
    • 第二个节点:0 × 2¹ = 0
    • 第三个节点:1 × 2⁰ = 1
    • 总和为 4+0+1=5

这种方法需要两次遍历链表,时间复杂度仍是 O (n),空间复杂度 O (1)。

【result += cur->val * (1 << length);详细解释】

这句话的作用是计算链表中当前节点值对应的十进制权重并累加到结果中,我们可以拆解来看:

  1. cur->val:当前链表节点的值(0 或 1,因为是二进制)

  2. 1 << length:这是 C 语言中计算 2 的幂的高效方式

    • << 是左移运算符,1 << n 表示将数字 1 的二进制向左移动 n 位
    • 等价于数学运算中的 2^length(2 的 length 次方)
    • 例如:1 << 3 等于 8(二进制 1000),即 2³=8
  3. 整体运算逻辑

    • 每个二进制位的十进制值 = 该位的值(0 或 1)× 2 的权重次方
    • 权重从最高位开始计算,例如二进制101
      • 第一位(最高位)1 的权重是 2²=4(1 << 2
      • 第二位 0 的权重是 2¹=2(1 << 1
      • 第三位 1 的权重是 2⁰=1(1 << 0
    • 所以 result += cur->val * (1 << length) 就是把当前位的十进制值累加到结果中

举例说明,对于链表1->0->1

  • 第一次循环(处理 1):length=2,计算 1 * (1 << 2) = 4,result=4
  • 第二次循环(处理 0):length=1,计算 0 * (1 << 1) = 0,result=4+0=4
  • 第三次循环(处理 1):length=0,计算 1 * (1 << 0) = 1,result=4+1=5

这样就得到了二进制101对应的十进制值 5。

【>>有吗,反正<<就是表示幂次吧】

在 C 语言中,<<(左移)和>>(右移)是位运算符,它们的本质是对二进制位进行移动操作,而不是直接表示幂次,只是左移运算在特定情况下可以等价于计算 2 的幂。

具体说明:

  1. 左移运算符 <<

    • 形式:a << n 表示将a的二进制位向左移动n位,右边补 0
    • a=1时,1 << n 恰好等于 2ⁿ(2 的 n 次方),这是因为:
      1 << 0 = 1(二进制1) → 2⁰ = 1
      1 << 1 = 2(二进制10) → 2¹ = 2
      1 << 2 = 4(二进制100) → 2² = 4
      1 << 3 = 8(二进制1000) → 2³ = 8
      
    • 但如果a不是 1,结果就不是单纯的幂次了,例如 3 << 2 = 12(二进制 11 左移 2 位变成 1100,即 12)
  2. 右移运算符 >>

    • 形式:a >> n 表示将a的二进制位向右移动n
    • 对于无符号数,左边补 0;对于有符号数,通常左边补符号位(正数补 0,负数补 1)
    • a是正整数时,a >> n 相当于 a ÷ 2ⁿ(整除),例如:
      8 >> 1 = 4(8 ÷ 2¹ = 4)
      8 >> 2 = 2(8 ÷ 2² = 2)
      15 >> 2 = 3(15 ÷ 2² = 3.75,取整为3)
      

总结:

  • << 和 >> 是位移动运算符,不是专门的幂运算符号
  • 1 << n 等价于 2ⁿ(仅这一种特殊情况可以理解为幂次)
  • a >> n 等价于 a ÷ 2ⁿ(正整数情况下,结果取整)

在之前的链表转整数代码中,用1 << length来计算 2 的幂,只是利用了左移运算的这个特性,比调用pow()函数更高效。

【我写的依旧错误的代码】

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
int getDecimalValue(struct ListNode* head) {struct ListNode *cur = head;int result = 0 ;while (cur != NULL){int x = 0;result = result + cur->val * (1 << x);x++;cur = cur -> next ; }return result;
}

你的代码逻辑存在一个关键问题:变量x在每次循环中都被重新初始化为 0,导致无法正确计算二进制位的权重。

具体来说,二进制链表的头部是最高位,而你的代码将每个节点都当作最低位(2⁰)来计算了。

例如对于链表1->0->1

  • 你的代码计算为:1×2⁰ + 0×2⁰ + 1×2⁰ = 1+0+1=2(错误)
  • 正确计算应该是:1×2² + 0×2¹ + 1×2⁰ = 4+0+1=5(正确)

修改后的代码如下:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
int getDecimalValue(struct ListNode* head) {struct ListNode *cur = head;int result = 0;int length = 0;// 先计算链表长度,确定最高位的权重while (cur != NULL) {length++;cur = cur->next;}// 重置指针到头部,准备计算结果cur = head;// 从最高位开始计算,权重是2^(length-1)int x = length - 1;while (cur != NULL) {result += cur->val * (1 << x);  // 正确计算当前位的权重x--;  // 每移动一个节点,权重降低一位cur = cur->next;}return result;
}

错误原因分析:

  1. 你的代码中int x = 0;放在了循环内部,导致每次循环x都会被重置为 0
  2. 这使得每个节点的值都被乘以 2⁰(即 1),无论它在链表中的位置
  3. 二进制转换需要根据位置计算不同的权重(从高位到低位依次是 2ⁿ⁻¹, 2ⁿ⁻², ..., 2⁰)

如果你想使用更简洁的方式,也可以采用一次遍历的方法:

int getDecimalValue(struct ListNode* head) {struct ListNode *cur = head;int result = 0;while (cur != NULL) {result = result * 2 + cur->val;  // 每次左移一位(乘以2)再加上当前值cur = cur->next;}return result;
}

这种方法更高效,通过逐步构建十进制数,避免了单独计算长度和权重的步骤。

原来就是一个数学问题呢.....

3 题解

如何遍历一个链表?代码框架如下:

// 遍历链表 head
while (head) { // 从链表头节点开始向后遍历,直到遇到空节点printf("%d\n", head->val); // 当前节点值head = head->next; // 准备遍历下一个节点
}

问题相当于给你一串 0 和 1,把它们拼成一个二进制数。

int getDecimalValue(struct ListNode* head) {int ans = 0;while (head) {ans = ans * 2 + head->val;head = head->next;}return ans;
}


复杂度分析

时间复杂度:O(n),其中 n 是链表的长度。
空间复杂度:O(1)。

http://www.dtcms.com/a/473541.html

相关文章:

  • 西安博达网站建设自己制作wordpress plugin
  • OpenCV的数据类型二
  • Serdes专题(3)Lattice Serdes架构
  • 人形机器人项目中使用Ubuntu-Server安装桌面系统进行远程xrdp远程连接操作
  • 京东开源了一款大模型安全框架:JoySafety,说是京东内部已应用,实现95%+攻击拦截率
  • 【传奇开心果系列】基于Flet框架实现的关于页面创建和提供文件下载集成了网络请求、文件下载、剪贴板操作功能自定义模板特色和实现原理深度解析
  • ​为什么我们需要将Flow转换为StateFlow?​​
  • vscode远程连接云服务器的初次尝试
  • 甘肃网站开发公司用手机怎么做免费网站
  • 网站是由多个网页组成的吗济南网约车平台
  • Linux系统下的终端,会话,shell,bash,进程组这几个概念的关系。
  • 微信小程序入门学习教程,从入门到精通,自定义组件与第三方 UI 组件库(以 Vant Weapp 为例) (16)
  • 银河麒麟V10高级服务器版Bash快捷键经常失效
  • 建设网站平台需要什么硬件配置电脑上买wordpress
  • Jessibuca 播放器
  • minio之docker的单机版安装
  • 主流 AI IDE 之一的 Qoder 和 Lingma IDE 介绍
  • 搜索不到网站的关键词国家企业信用公示系统官网查询
  • PostgreSQL在Linux中的部署和安装教程
  • AI大事记12:Transformer 架构——重塑 NLP 的革命性技术(上)
  • PostgreSQL JDBC 连接参数大全
  • 【SpringBoot从初学者到专家的成长11】Spring Boot中的application.properties与application.yml详解
  • 简述你对于网站建设的认识h5微网站开发
  • OpenHarmony IMF输入法框架全解析:从原理到自定义输入法开发实战指南
  • LabVIEW的PID控制器带报警仿真系统
  • WordPress--代码块添加折叠和展开功能
  • 爱站网能不能挖掘关键词做网站Linux
  • 在单台电脑上管理多个 GitHub 账户并解决推送问题
  • 计算机毕设选题推荐:基于Hadoop和Python的游戏销售大数据可视化分析系统
  • kanass入门到实战(17) - 如何进行工时管理,有效度量项目资源