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自动插入数据的方式定义列。 …...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...