不用加减乘除做加法_牛客题霸_牛客网 (nowcoder.com)
可以使用位运算符实现两个整数的加法:
在二进制加法中,我们通常使用“逐位相加”的方法来模拟常规加法的过程。当两个数字进行加法运算时,从最低位(通常是右侧)开始相加,然后考虑进位。如果相加的结果产生进位,那么这个进位会被带到下一位的加法中。
while (b != 0)
循环是为了确保所有的位都被正确地相加,并处理了所有可能的进位。这里 b
实际上充当了一个“进位标志”的角色。只要 b
不为0,说明还有进位需要处理,所以循环会继续执行。
具体来说:
- 当
b
为0时,意味着没有进位,加法运算已经完成。 - 当
b
不为0时,表示还有进位需要加到下一位上。这时,通过a = a ^ b;
计算当前位(不考虑进位的和),然后通过b = carry << 1;
将进位左移一位(即考虑到下一位的加法中)。
这种算法通常被称为“无进位加法”或“二进制加法”,它模仿了人类手动进行二进制数加法的过程。通过不断迭代,直到没有进位为止(即 b
为0),最终得到两个二进制数的和。
简而言之,while (b != 0)
循环确保了所有位都被正确相加,并且处理了所有可能的进位,直到得到一个最终的和,其中没有进一步的进位需要处理。
在二进制加法中,b = carry << 1;
这一步是将进位(carry
)左移一位。这模拟了在传统的十进制加法中,当两个数字相加的和超过9时,我们会进一位到更高的数位。在二进制中,这个概念类似,只是数字变成了2而不是10。
让我们分解这一步:
-
进位(
carry
): 在二进制加法中,carry
变量存储了上一轮加法运算产生的进位。这个进位是那些在两个相加数字的对应位上都是1的位产生的。在二进制中,1 + 1 = 10,所以产生了一个进位(1)和一个输出位(0)。 -
左移一位(
<< 1
): 在计算机中,左移操作等同于乘以2。因此,将进位值左移一位实际上是将它乘以2。在二进制加法中,这表示将进位传递到更高的位。例如,如果在最低位(第0位)有一个进位,左移一位后,这个进位就会出现在下一位(第1位)。 -
更新
b
:b
变量在算法中扮演着双重角色。在最开始的迭代中,它是第二个加数。但在后续的迭代中,它存储了从上一次迭代传递下来的进位。因此,b = carry << 1;
更新了b
的值,以便在下一次循环迭代中处理这个进位。
这个过程重复进行,直到没有进位(b == 0
)为止。每次迭代都处理一对位,并可能产生一个新的进位,这个进位在下一次迭代中被处理。最终,当没有更多的进位需要处理时,算法完成,a
变量中存储的就是两个原始数字的和。
总结来说,b = carry << 1;
这一步是二进制加法中的关键部分,它负责将进位传递到更高的位,并准备在下一次循环迭代中处理这个进位。
#include <stdio.h>
int addWithoutArithmetic(int a, int b) {
while (b != 0) {
int carry = a & b; //这步操作找出两个数在相同位置都为1的位,这些位将在加法中产生进位
a = a ^ b; //得到没有考虑进位的加法结果。这步操作找出两个数在不同位置为1的位,这些位将在加法中产生1
b = carry << 1;
}
return a;
}
int main() {
int num1 = 5;
int num2 = 3;
int sum = addWithoutArithmetic(num1, num2);
printf("The sum of %d and %d is %d\n", num1, num2, sum);
return 0;
}
448. 找到所有数组中消失的数字 - 力扣(LeetCode)
代码使用了一种巧妙的方法,即利用数组元素的正负性来标记其是否出现过,从而找出缺失的数字 。
#include <stdio.h>
#include <stdlib.h>
int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize)
//接受一个整数数组nums、数组的大小numsSize,以及一个用于返回结果数组大小的指针returnSize{
// 遍历数组,将元素对应的索引位置上的元素取负值
for (int i = 0; i < numsSize; i++) { //遍历数组nums,将元素对应的索引位置上的元素取负值。因为数组中的元素范围是1到n,所以我们用abs(nums[i]) - 1来得到对应的索引(减1是因为数组索引从0开始)。如果索引i上的元素是正数,就将其取负值,表示这个数字出现过
int index = abs(nums[i]) - 1; // 将元素值转换为索引,因为元素值在1到n之间
if (nums[index] > 0) { // 确保不会对一个负数取反
nums[index] = -nums[index];
}
}
// 找出那些仍然为正数的索引,这些索引对应的数字就是缺失的数字
int* result = (int*)malloc(numsSize * sizeof(int));
int count = 0;
for (int i = 0; i < numsSize; i++) { //再次遍历数组nums,找出那些仍然为正数的索引。这些索引对应的数字就是缺失的数字。对于每个正数索引i,将i + 1(因为缺失的数字范围也是1到n)添加到结果数组result中,并增加计数器count
if (nums[i] > 0) {
result[count++] = i + 1; // 将索引转换为缺失的数字,并计数
}
}
// 设置返回数组的大小
*returnSize = count;
return result;
}
int main() {
int nums[] = {4, 3, 2, 7, 8, 2, 3, 1};
int numsSize = sizeof(nums) / sizeof(nums[0]);
int returnSize;
int* result = findDisappearedNumbers(nums, numsSize, &returnSize);
printf("The missing numbers are: ");
for (int i = 0; i < returnSize; i++) {
printf("%d ", result[i]);
}
printf("\n");
// 释放结果数组的空间
free(result);
return 0;
}