C语言——小知识和小细节18

一、力扣题目

1、题目本体

2、题解

本题目我们使用异或分组的方法来解决。可以在我之前的文章《C语言——操作符CSDN博客》中看一下异或的特点。

由于异或的运算规则为相同为0,不同为1,而且是在二进制补码上进行操作的,我们可以发现的一个特点就是相同的数字异或的结果是0,利用这一点,我们好像就对上面的题目有了些许想法。

对于整个数组,只有两个出现一次的数字,其他的数字都是出现两次的,所以们可以发现,如果我们将数组所有的元素都异或起来,结果就是两个只出现一次的两个数字异或起来的结果。就像下面:

    int res = 0;
    int i = 0;
    for (i = 0; i < numsSize; i++) {
        res ^= nums[i];
    }

然后我们得到的这个res就是可以反映这两个只出现一次的数字的不同的位的,下面举个例子:

假设两个只出现一次的数字是 5 和 6,它们的二进制为101和110,异或后得到的结果的二进制为011。然后我们得到这个结果的目的就是将这两个不同的数字分开,可以发现结果中为 1 的位,也是这两个数字的不同的位,我们可以直接取到结果中第一个为1的位,通过这个位来将两个数分在不同组中,然后分别将两个组异或起来,就可已得到这两个数字。

3、代码

int* singleNumber(int* nums, int numsSize, int* returnSize) {
    int res = 0;
    int i = 0;
    for (i = 0; i < numsSize; i++) {
        res ^= nums[i];
    }
    int pos = 0;
    for (pos = 0; pos < 32; pos++) {
        if (((res >> pos) & 1) == 0) {
            break;
        }
    }
    int num1 = 0;
    int num2 = 0;
    for (i = 0; i < numsSize; i++) {
        if (((nums[i] >> pos)& 1) == 0) {
            num1 ^= nums[i];
        }
        else {
            num2 ^= nums[i];
        }
    }
    int* ans = (int*)malloc(2 * sizeof(int));
    ans[0] = type1;
    ans[1] = type2;
    *returnSize = 2;
    return ans;
}

4、解释

    for (i = 0; i < numsSize; i++) {
        res ^= nums[i];
    }

将数组中所有元素异或起来,得到 res 。

    for (pos = 0; pos < 32; pos++) {
        if (((res >> pos) & 1) == 0) {
            break;
        }
    }

用来找到 res 中第一个为1的位,然后使用 pos 变量来保存这个位是第几位,以便后面使用。

    int num1 = 0;
    int num2 = 0;
    for (i = 0; i < numsSize; i++) {
        if (((nums[i] >> pos)& 1) == 0) {
            num1 ^= nums[i];
        }
        else {
            num2 ^= nums[i];
        }
    }

这一步完成分组和分别将两个组的元素都异或起来,两步合在了一起。

    if (((nums[i] >> pos)& 1) == 0) {
        num1 ^= nums[i];
    }

如果数组中的元素的 pos 位也为 1 的话就分一组,然后依次异或起来,这时那两个只出现一次的数字已经被分开,这里只有其中之一。

    else {
        num2 ^= nums[i];
    }

如果数组中的元素的 pos 位0为 0 的话就分一组,然后依次异或起来,0,这里只有其中另一。

这样的活,其他相同的数字被分到哪一组都无所谓,它们两个一对会被分到一组,因为两个相同的数字的同一位是相同的。这样异或起来,最后,num1 和 num2 中就剩下那两个只出现一次的数字了。

二、模拟实现atoi函数

1、atoi函数介绍

在C语言中,atoi(ASCII to Integer)是一个标准库函数,用于将表示整数的字符串转换为其对应的整数值。该函数定义在stdlib.h头文件中。

函数原型

int atoi(const char *str);

参数

str:指向一个以空字符('\0')结尾的字符串,该字符串表示一个整数。

参数

返回转换后的整数值。
如果字符串中不包含合法的整数,atoi的行为未定义,可能返回0或其他值。

2、模拟实现

#include <stdio.h>
#include <limits.h>

int my_atoi(const char* str) {
	const char* string = str;
	while (*string == ' ') {//跳过前置空格
		string++;
	}
	int flag = 0;
	if (*string == '-') {//判断数字正负
		flag = -1;
		string++;
	}
	else if (*string == '+') {
		flag = 1;
		string++;
	}
	long long retValue = 0;
	while (*string) {//计算数字本体
		if (*string <= '9' && *string >= '0') {
			retValue = retValue * 10 + (long long)((*string - '0') * flag);
			if (retValue > INT_MAX || retValue < INT_MIN) {//判断是否越界
				return 0;
			}
		}
		else {
			return (int)retValue;
		}
		string++;
	}
	return (int)retValue;
}

int main() {
	char str[] = "    -123878";
	int res = my_atoi(str);
	printf("%d", res);
	return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值