每日一题 (不用加减乘除做加法,找到数组中消失的数字)

简介: 每日一题 (不用加减乘除做加法,找到数组中消失的数字)

不用加减乘除做加法_牛客题霸_牛客网 (nowcoder.com)

可以使用位运算符实现两个整数的加法:

在二进制加法中,我们通常使用“逐位相加”的方法来模拟常规加法的过程。当两个数字进行加法运算时,从最低位(通常是右侧)开始相加,然后考虑进位。如果相加的结果产生进位,那么这个进位会被带到下一位的加法中。

while (b != 0) 循环是为了确保所有的位都被正确地相加,并处理了所有可能的进位。这里 b 实际上充当了一个“进位标志”的角色。只要 b 不为0,说明还有进位需要处理,所以循环会继续执行。

具体来说:

  1. b 为0时,意味着没有进位,加法运算已经完成。
  2. b 不为0时,表示还有进位需要加到下一位上。这时,通过 a = a ^ b; 计算当前位(不考虑进位的和),然后通过 b = carry << 1; 将进位左移一位(即考虑到下一位的加法中)。

这种算法通常被称为“无进位加法”或“二进制加法”,它模仿了人类手动进行二进制数加法的过程。通过不断迭代,直到没有进位为止(即 b 为0),最终得到两个二进制数的和。

简而言之,while (b != 0) 循环确保了所有位都被正确相加,并且处理了所有可能的进位,直到得到一个最终的和,其中没有进一步的进位需要处理。

在二进制加法中,b = carry << 1; 这一步是将进位(carry)左移一位。这模拟了在传统的十进制加法中,当两个数字相加的和超过9时,我们会进一位到更高的数位。在二进制中,这个概念类似,只是数字变成了2而不是10。

让我们分解这一步:

  1. 进位(carry: 在二进制加法中,carry 变量存储了上一轮加法运算产生的进位。这个进位是那些在两个相加数字的对应位上都是1的位产生的。在二进制中,1 + 1 = 10,所以产生了一个进位(1)和一个输出位(0)。
  2. 左移一位(<< 1: 在计算机中,左移操作等同于乘以2。因此,将进位值左移一位实际上是将它乘以2。在二进制加法中,这表示将进位传递到更高的位。例如,如果在最低位(第0位)有一个进位,左移一位后,这个进位就会出现在下一位(第1位)。
  3. 更新 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;  
}
相关文章
|
17天前
|
算法 测试技术 C#
【位运算】【脑筋急转弯】2749. 得到整数零需要执行的最少操作数
【位运算】【脑筋急转弯】2749. 得到整数零需要执行的最少操作数
|
4月前
|
C语言
C语言第四十六弹---最快方法找到杨氏矩阵中的数下标
C语言第四十六弹---最快方法找到杨氏矩阵中的数下标
|
4月前
|
C语言
C语言第二十八弹--输入一个非负整数,返回组成它的数字之和
C语言第二十八弹--输入一个非负整数,返回组成它的数字之和
|
6月前
|
算法
【每日挠头算法(4)】字符串相加|字符串相乘
【每日挠头算法(4)】字符串相加|字符串相乘
|
6月前
|
C语言
乘法口诀标的打印及解释
打印乘法口诀表可以说是c语言中一个很经典的一个简单程序了。 打印乘法口诀表的第一反应可能会是很难,怎么打印出这么多相乘的数呢。但是仔细想分析和考虑的话,其实很简单。那么我来说一下打印乘法口诀表的思路。
29 0
|
9月前
学C的第十三天【应用多文件的形式实现 三子棋 程序(重点);练习:1. 打印9*9乘法口诀表、2. 求10个整数中的最大值、3. 分数加减交叉计算、4. 数一下 1到 100 的整数中出现了多少个9】
9.数组的应用实例1:三子棋(综合以前学习的知识) 三子棋的实现:(重点都在注释中) 1. 游戏不退出,继续玩下一把(循环) 2. 应用多文件的形式写代码
|
9月前
|
C语言
【C语言】 找到所有数组中消失的数字(超详细)
【C语言】 找到所有数组中消失的数字(超详细)
124 0