一、力扣题目
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;
}
运行结果: