Leetcode 面试题 17.01 不用加号的加法

设计一个函数把两个数字相加。不得使用 + 或者其他算术运算符。
示例:
输入: a = 1, b = 1 输出: 2
提示:
a,b均可能是负数或 0- 结果不会溢出 32 位整数
我的答案:
一、信息
1.设计一个函数把两个数相加
2.不得使用+或者其他运算符
3.a,b均为负数或0
4.结果不会溢出32位整数
二、分析
问题出现:
1.如何实现不用加法就实现两数相加呢?
我的思路:
思路1:通过将a,b转化成二进制,这样我们就能用二进制加法求解了。
新的问题出现:
该如何实现二进制加法呢?
首先我们可以观察二进制加法的规律
1101
+1010
10111
规律就是:
1 0 得1
1 1 得0
0 0 得0
我的答案其实很简单我们只需要通过与异或运算即可实现
问题2:该如何避免结果不会溢出32位整数呢?
我的实现:
为了不使用`+`或其他算术运算符来实现数字的加法,我们可以使用位操作。以下是基于此思路的解决方案:
### 1. C语言:
#include <stdio.h>int add(int a, int b) {while (b != 0) {unsigned int carry = (unsigned int)(a & b) << 1; // 计算进位a = a ^ b; // 不计算进位的加法b = carry; // 把进位放在b上,继续进行加法}return a;
}int main() {int a = 1, b = 1;printf("Sum: %d\n", add(a, b));return 0;
}
2. C++:
#include <iostream>int add(int a, int b) {while (b != 0) {unsigned int carry = (unsigned int)(a & b) << 1;a = a ^ b;b = carry;}return a;
}int main() {int a = 1, b = 1;std::cout << "Sum: " << add(a, b) << std::endl;return 0;
}
JAVA:
public class AddWithoutPlus {public static int add(int a, int b) {while (b != 0) {int carry = a & b; // 计算进位a = a ^ b; // 不计算进位的加法b = carry << 1; // 把进位放在b上,继续进行加法}return a;}public static void main(String[] args) {int a = 1, b = 1;System.out.println("Sum: " + add(a, b));}
}
这些解决方案都是基于二进制表示的加法原理,利用位操作来实现的。当我们加两个二进制数时,可以分为两步:1) 不计算进位的加法,和 2) 计算进位。
英雄师傅的分析:
将a和b都转化成二进制以后,执行相加,举个简单的例子,例如a是21(二进制是10101),b是12(二进制是1100),它们两个相加的值应该是33
对于两个数的对应相加,如果不产生进位就是异或的结果。(在我看来就是用异或来模拟这个过程)
比如说:
唯一没有提到的,就是1和1相加的情况,这种情况会产生进位,所以异或结果并不等于相加的结果,但是异或的结果等于相加后低位的值。换言之1+1=10,异或结果等于0,0和0相等,很合理。
基于上述观点,如果两个数二进制在相加的过程中,都没有出现1和1的情况,那么加法就等于两个数的异或。如果有进位,那么就要把进位的那部分单独拎出来。
什么时候有进位呢?当两个都为1的时候,也就是两个位与为1的时候,所以我们可以把a+b拆成两个部分
a^b和a&b
英雄师傅的实现过程:
int add(int a, int b){if(b==0){return a;}return add(a^b,((unsigned int)(a&b))<<1);
}
Leetcode 题解
Leetcode地址:Leetcode题解
方法一:位运算
预备知识
有符号整数通常用补码来表示和存储,补码具有如下特征:
正整数的补码与原码相同;负整数的补码为其原码除符号位外的所有位取反后加 111。
可以将减法运算转化为补码的加法运算来实现。
符号位与数值位可以一起参与运算。
思路和算法
虽然题目只要求了不能使用算术运算符,但是原则上来说也不宜使用类似的运算符 +=\texttt{+=}+= 和 -=\texttt{-=}-= 以及 sum\texttt{sum}sum 等方法。于是,我们使用位运算来处理这个问题。
首先,考虑两个二进制位相加的四种情况如下:
0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 0 (进位)
可以发现,对于整数 aaa 和 bbb:
在不考虑进位的情况下,其无进位加法结果为 a⊕b\texttt{a} \oplus \texttt{b}a⊕b。
而所有需要进位的位为 a & b\texttt{a \& b}a & b,进位后的进位结果为 (a & b) << 1\texttt{(a \& b) << 1}(a & b) << 1。
于是,我们可以将整数 aaa 和 bbb 的和,拆分为 aaa 和 bbb 的无进位加法结果与进位结果的和。因为每一次拆分都可以让需要进位的最低位至少左移一位,又因为 aaa 和 bbb 可以取到负数,所以我们最多需要 log(max_int)\log (max\_int)log(max_int) 次拆分即可完成运算。
因为有符号整数用补码来表示,所以以上算法也可以推广到 000 和负数。
实现
在 C++\texttt{C++}C++ 的实现中,当我们赋给带符号类型一个超出它表示范围的值时,结果是 undefined\text{undefined}undefined;而当我们赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模的余数。因此,我们可以使用无符号类型来防止溢出。
在 Python\texttt{Python}Python 的实现中,因为 Python\texttt{Python}Python 的整数类型为是无限长的,所以无论怎样左移位都不会溢出。因此,我们需要对 Python\texttt{Python}Python 中的整数进行额外处理,以模拟用补码表示的 323232 位有符号整数类型。具体地,我们将整数对 2322^{32}2
32
取模,从而使第 333333 位及更高位均为 000;因为此时最终结果为用补码表示的包含符号位的 323232 位整数,所以我们还需要再次将其换算为 Python\texttt{Python}Python 的整数。
C++:
class Solution {
public:int add(int a, int b) {while (b != 0) {unsigned int carry = (unsigned int)(a & b) << 1;a = a ^ b;b = carry;}return a;}
};
JAVA:
class Solution {public int add(int a, int b) {while (b != 0) {int carry = (a & b) << 1;a = a ^ b;b = carry;}return a;}
}
总结:
个人
从这个问题中,我们可以学到多方面的知识和技能:
1. **基础计算机科学知识**:这道题目介绍了如何使用位操作来模拟基本的算术运算,这反映了计算机在底层如何处理加法。
2. **递归和迭代思维**:即使在这样的问题中,递归和迭代的应用也是一个重要的思维模式。我们反复应用相同的逻辑,直到达到预期的结果。
3. **处理边界情况**:考虑到整数溢出和32位限制,这提醒我们在解决问题时总是要注意潜在的边界情况和限制。
4. **位操作技能**:位操作是许多算法和数据结构问题中的一个关键技能。这道题目为我们提供了一次实际应用的机会,加深了我们对`AND`、`XOR`、左移等操作的理解。
5. **创新思维**:当面对某些明显的方法(例如使用加法运算符)不可用时,寻找其他解决方案需要创新思维。这种思维方式对于不断发展的计算机科学领域是至关重要的。
6. **优化和效率**:尽管我们可以使用递归来解决此问题,但递归可能会导致效率问题,特别是对于大的整数。这提醒我们,即使某个方法是可行的,我们仍然需要考虑其效率。
7. **实际应用与理论知识**:在真实的计算机系统中,加法和其他算术操作确实是通过硬件逻辑(例如加法器)和位操作来实现的。通过这种方法,我们不仅学习了一种算法技巧,而且还深入了解了计算机的工作原理。
总的来说,这道题目为我们提供了一次深入学习计算机科学基础、算法设计和优化的机会,并激发了我们的创新思维。
感受:
其实这道题目和计算机组成原理中定点加法和减法这一章很像,象在哪里呢?其实就是像在对二进制加法的推导和探索,其中二者都处理了很多进位问题。其实我觉得出题人是想让我们体验一把当初计算机科学家们是如何一步一步设计出加法器的,就是绕开编译器原本就带着的+法函数而是自己写一个这个函数的底层。
(传送门:计算机组成原理 2.2 定点加法)

相关文章:
Leetcode 面试题 17.01 不用加号的加法
设计一个函数把两个数字相加。不得使用 或者其他算术运算符。 示例: 输入: a 1, b 1 输出: 2 提示: a, b 均可能是负数或 0结果不会溢出 32 位整数 我的答案: 一、信息 1.设计一个函数把两个数相加 2.不得使用或者其他运算符 3.a,b均为负数或…...
一个 MySQL 数据库死锁的案例和解决方案
本文介绍了一个 MySQL 数据库死锁的案例和解决方案。 场景 生产环境出了一个偶现的数据库死锁问题,导致少部分业务处理失败。 分析特征之后,发现是多个线程并发执行同一个方法,更新关联的数据时可能会出现,把场景简化概括一下&…...
AMBEO 双声道空间音频现已迈进直播制作领域
图片来源:Unsplash,作者:Bence Balla-Schottner AMBEO 双声道空间音频现已迈进直播制作领域 为所有观众解锁更加身临其境的听觉体验 森海塞尔将功能强大的 AMBEO 双声道空间音频技术引入了广播电视直播应用领域,对所有体育赛事广…...
在VSCode上画UML的三个插件
2023年9月2日,周六晚上 因为写代理模式的博客时需要画UML,所以就在网上找了半天, 最后觉得VSCode上的这三个插件比较好用 目录 三个画UML的VSCode插件PlantUMLDraw.io IntegrationUMLet我个人推荐使用PlantUML 三个画UML的VSCode插件 Pla…...
Springboot - 1.什么是springboot
👀Spring的核心模块 Spring Framework是一个功能强大的开源框架,用于构建Java企业级应用程序。它提供了多个核心模块,每个模块都提供不同的功能,用于解决应用程序开发中的各种问题。以下是Spring Framework的核心模块的全面解析&…...
学习微信小程序 Westore
最近,接到小程序需求,并且是在以前公司老项目上改造,打开项目,发现却不是我想象中的那样,不是上来就是 Page({}),而是create(store,{}),纳尼???这什么玩意&am…...
CentOS上使用Docker安装和部署kkFileView
🎈1 参考文档 kkFileView官方文档 🚀2 安装kkFileView 拉取Redis镜像。 docker pull keking/kkfileview启动docker容器。 docker run -it -d -p 8012:8012 keking/kkfileview --restart always解释: docker run redis # 从kkfileview镜像运行…...
Level-based Foraging 多智能体游戏仿真环境
游戏场景测试 参考链接: https://kgithub.com/semitable/lb-foraging...
LeetCode-53-最大子数组和-贪心算法
贪心算法理论基础: 局部最优推全局最优 贪心无套路~ 没有什么规律~ 重点:每个阶段的局部最优是什么? 题目描述: 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素&#…...
解决gitee仓库中 .git 文件夹过大的问题
最近,许多项目都迁移到gitee。使用的也越来越频繁,但是今天突然收到一个仓库爆满的提示。让我一脸懵逼。本文将详细为你解答,这种情况如何处理。 1、起因 我收到的报错如下: remote: Powered by GITEE.COM [GNK-6.4] remote: T…...
uniapp 开发小程序,封装一个方法,让图片使用线上地址
1.在main.js文件中,添加以下代码: 复制使用: // 图片使用网络地址 Vue.prototype.localImgSrc function(img){//项目的地址域名,例如百度return "https://baidu.cn/static/index/images/" img; }2.在页面中直接使用&…...
Android 12 源码分析 —— 应用层 三(SystemUIFactory及其Dependency解析)
Android 12 源码分析 —— 应用层 三(SystemUIFactory及其Dependency解析) 在上一篇文章中,介绍了SystemUI的启动流程,并且简单提及了Dagger2用来管理各个SystemUI中要用的依赖。而这部分代码就在:mContextAvailableC…...
考前冲刺上岸浙工商MBA的备考经验分享
2023年对于许多人来说都是不平凡的一年,历经三年的抗争,我们终于成功结束了疫情。而我也很幸运的被浙工商MBA项目录取,即将开始全新的学习生活。身为一名已在职工作6年的人,能够重回校园真是一种特别令人激动的体验。今天…...
XmlDocument.SelectNodes 不起作用
今天采用Xpath读取Xml节点,怎么都读不出。 问题分析: 错误代码如下: XmlDocument xmlD new XmlDocument();xmlD.PreserveWhitespace true;xmlD.LoadXml(xStr);xmlD.SelectNodes("job-scheduling-data/schedule/job");经排查 do…...
部署单点elasticsearch
部署elasticsearch 创建网络 因为我们还需要部署kibana容器,因此需要让es和kibana容器互联。这里先创建一个网络 docker network create es-net 拉取镜像 我们采用elasticsearch的7.12.1版本的镜像 docker pull elasticsearch:7.12.1 运行 运行docker命令&a…...
ElementUI浅尝辄止16:Tag 标签
用于标记和选择。 1.如何使用? 由type属性来选择tag的类型,也可以通过color属性来自定义背景色。<el-tag>标签一</el-tag> <el-tag type"success">标签二</el-tag> <el-tag type"info">标签三</e…...
Java虚拟机(JVM)框架
见:GitHub - eHackyd/Java_JVM: Java虚拟机(JVM)框架的学习笔记...
配置Publisher 的编译规则
步骤 1:创建ROS Package 使用以下命令创建一个新的ROS软件包: catkin_create_pkg my_publisher_package roscpp std_msgs步骤 2:编辑 CMakeLists.txt 文件 打开您的ROS软件包的 CMakeLists.txt 文件,通常位于软件包的根目录。您…...
【SpringBoot】接口实现:SpringBoot实现博客系统的文章列表页接口代码
以下是一个简单的Spring Boot博客系统的文章列表页接口代码示例: java RestController RequestMapping("/articles") public class ArticleController {Autowiredprivate ArticleService articleService;GetMapping("/")public List<Artic…...
如何使用SQL系列 之 如何在SQL中插入数据
简介 结构化查询语言,通常被称为SQL,在允许您将数据插入表中方面提供了极大的灵活性。例如,你可以使用VALUES关键字指定单独的行数据,使用SELECT查询从现有表中复制整组数据,以及以使SQL自动插入数据的方式定义列。 …...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...
