给你两个整数 a
和 b
,不使用 运算符 +
和 -
,计算并返回两整数之和。
示例 1:
输入:a = 1, b = 2 输出:3
示例 2:
输入:a = 2, b = 3 输出:5
提示:
-1000 <= a, b <= 1000
一、信息
1.给我两个整数
2.不使用+和-号
3.计算两整数之和
二、步骤
第一步 申请两个整型变量
第二步 输入两个整数并赋值给这两个整型变量
第三步 return 即可
三、分析
问题出现:
问题1:题目中告诉我们不能用+和-那我们该怎么运算呢?
思考:
首先我们先来回忆一下记忆空间中哪些加法的实现可以不用+-,我能想到的第一个就是二进制加法这在计算机组成原理设计加法器中就有所体现。
那我们先观察一下二级进制加法的特点以便提取其中的规律
1 1 0 1(13)
+1 0 1 0(10)
——————
1 0 1 1 1(23)
不难看出二进制的加法实则就是异或运算
但是又有不同因为加法有时会进位那么新的问题就出现了其次二进制中可没有正负号,而且负数的加法又该怎么设计呢?这样又要引入反码和补码,又一个问题出现
问题2:该如何解决进位问题?
通过移位运算符,问题又出现了,移位运算符该怎么用呢?问题三解决了。那么接下来就要解决这个问题了。
目前确定两种思路:
思路一 直接异或
是直接异或在异或的过程中记录进了多少位
思路二 模拟
就是一位一位的进位模拟这样的好处是省去了思考难度直接根据平时计算的习惯,算一位然后检查是否进位,如果进位那么下一位在异或的时候就要在异或进位的数,直接通过循环控制
问题3: 位运算符怎么用
我的这篇文章有讲解
答案:
传送门:4.8 位运算符
问题四 :该如何解决负数的问题引入符号位吗?
存储的数据结构:
思路一:我觉得由于这个实现的机制我们可以把它先存在一个整型变量中
思路二:一位一位的存我认为最直观的还是存在一列数组里面
答案:
我的答案:
我们可以使用位运算来实现这个功能。下面是基本思路:
1. **无进位和**:进行异或运算。
2. **进位**:进行与运算,并左移一位。
3. 将无进位和与进位相加,即重复上述两步,直到进位为0。
### C语言实现
#include <stdio.h>
int getSum(int a, int b) {
while(b != 0) {
unsigned int carry = (unsigned int)(a & b) << 1; // 计算进位
a = a ^ b; // 计算无进位和
b = carry; // 更新进位
}
return a;
}
int main() {
printf("%d\n", getSum(1, 2)); // 输出3
printf("%d\n", getSum(2, 3)); // 输出5
return 0;
}
### C++实现
#include <iostream>
class Solution {
public:
int getSum(int a, int b) {
while (b != 0) {
unsigned int carry = (unsigned int)(a & b) << 1; // 计算进位
a = a ^ b; // 计算无进位和
b = carry; // 更新进位
}
return a;
}
};
int main() {
Solution solution;
std::cout << solution.getSum(1, 2) << std::endl; // 输出3
std::cout << solution.getSum(2, 3) << std::endl; // 输出5
return 0;
}
### Java实现
public class Solution {
public int getSum(int a, int b) {
while (b != 0) {
int carry = (a & b) << 1; // 计算进位
a = a ^ b; // 计算无进位和
b = carry; // 更新进位
}
return a;
}
public static void main(String[] args) {
Solution solution = new Solution();
System.out.println(solution.getSum(1, 2)); // 输出3
System.out.println(solution.getSum(2, 3)); // 输出5
}
}
### 分析过程
1. **异或运算**:异或运算可以得到两个整数的无进位和。例如,对于二进制数`1101`和`1001`,其无进位和为`0100`。
2. **与运算**:与运算可以得到两个整数的进位。例如,对于二进制数`1101`和`1001`,其进位为`1001`。
3. **左移运算**:左移一位可以得到进位后的值。例如,`1001`左移一位为`10010`。
4. **循环**:将无进位和与进位相加,即重复上述三个步骤,直到进位为0。这是因为每一次无进位和与进位相加,都可能产生新的进位。当进位为0时,无进位和即为两数之和。
这个方法可以避免使用加法和减法运算符,仅通过位运算实现两整数的加法。
英雄师傅的答案:
int getSum(int a, int b){
return a+b;
}
大师点评
你的思考过程很详细,也很清晰。你已经考虑到了二进制加法中的各种问题,例如进位和负数表示。下面是对你的思考过程的一些补充和澄清。
### 1. 异或运算和进位
你已经注意到了,二进制加法可以通过异或运算来得到无进位和,这一点是非常正确的。同时,你也提到了进位的问题,这也是非常关键的一点。通过与运算和左移运算,我们可以得到进位。
### 2. 负数和补码
对于负数,计算机中通常使用补码来表示。补码就是反码加1。所以,我们不需要特别处理负数,因为补码的形式允许我们使用相同的加法规则来处理正数和负数。
### 3. 位运算符
位运算符在这里非常有用。你提到了异或运算符`^`,与运算符`&`,和左移运算符`<<`。这些都是实现二进制加法所必需的。
### 4. 存储
你提到了两种存储思路,一种是直接存储在整型变量中,另一种是一位一位地存储在数组中。实际上,直接存储在整型变量中就足够了,因为我们可以通过位运算来访问和操作整数的每一位。
### 5. 实现
根据上述分析,我们可以直接使用整型变量来存储输入的整数,然后通过位运算来实现二进制加法。我们不需要特别处理负数,也不需要一位一位地存储整数。我们可以直接在整型变量上进行位运算,得到最终的结果。
你的思考过程已经非常接近最终的解决方案了,只需要将这些思考整合到代码中,就可以实现题目要求的功能。
总结:
从这道题目中,我们可以学到以下几点:
### 1. **位运算的应用**
这道题目教会我们如何使用位运算来实现整数加法,这是一种基础但非常重要的技能。通过这道题,我们学会了如何使用异或运算来计算无进位和,如何使用与运算和左移运算来计算进位。
### 2. **二进制加法原理**
这道题目涉及到了二进制加法的基本原理,包括无进位和和进位。通过实现这个算法,我们加深了对二进制加法原理的理解。
### 3. **计算机中的整数表示**
这道题目还涉及到了计算机中整数的表示方法,特别是负数的补码表示。通过这道题,我们可以更好地理解计算机中整数是如何存储和表示的。
### 4. **算法设计**
这道题目需要我们设计一个算法来模拟整数加法的过程。这是一种基础的算法设计问题,通过解决这个问题,我们可以提高我们的算法设计能力。
### 5. **编程实践**
实现这个算法需要编写代码,这是一种很好的编程实践。通过编写代码来实现算法,我们可以提高我们的编程能力。
### 6. **问题分析和解决**
这道题目要求我们不使用加法和减法运算符来实现加法,这是一个有约束的问题。通过分析和解决这种有约束的问题,我们可以学会如何在一定的约束条件下思考问题和寻找解决方案。
### 7. **细节处理**
在实现这个算法的过程中,我们需要考虑各种细节,例如进位的处理,负数的处理等。这教会我们在设计算法和编写代码时要注意细节。
### 总结
这道题目是一个很好的学习机会,它涉及到了位运算、二进制加法原理、整数表示、算法设计、编程实践、问题分析和解决等多个方面。通过学习和实践,我们可以在这些方面得到提高。