题目 1
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
#include<stdio.h>
int main()
{
int arr[] = { 1, 3, 8, 1, 3, 8, 4, 6 };
int num = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
int pos = 0;
int x = 0;
int y = 0;
for (i = 0; i < sz; i++)//异或
{
num ^= arr[i];
}
printf("num=%d\n");
for (i = 0; i < 32; i++)//找num的二进制中为1的一个为pos
{
if (1 == (num >> i) & 1)
{
pos = i;
break;
}
}
for (i = 0; i < sz; i++)//分组
{
if (((arr[i] >> pos) & 1) == 1)
{
x ^= arr[i];
}
else
{
y ^= arr[i];
}
}
printf("x=%d y=%d\n", x, y);
system("pause");
return 0;
}
题目2:
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
思路:两个数相加可以看成,每个位数上的数相加但不进位,然后再和进位的数相加。
先思考十进制的数:如18+5 看成1+0=1 8+5=3得到13和进一个十位数10,然后再13+10,
可以看成1+1=2 3+0=3得到23,进位为0,所以结束,得到最后的结果。
然后看二进制的数:3+3 3: 00000011
0+0=0,1+1=0,1+0=1——这相当于按位亦或的到未进位的数 ;
在二进制中,逢二进一,如11+11=110,可以看成11&11=11 11<<1=110
3+3看成 00000011+00000011=00000000 00000011<<1=00000110 00000000+00000110=00000110为6
int Add(int num1, int num2)
{
while (num2 != 0)//进位为0的时候退出循环
{
int tmp = num1 ^ num2;//按位亦或——没有进位的相加
num2 = num1 & num2 << 1;//得到进位的数
num1 = tmp;//num1接受没有进位相加的结果
}
return num1;
}
题目3:
给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。
请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
低级算法:
低阶方法
#include<stdlib.h>
int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize)
{
*returnSize = 0;
int count = 0;
int* p = (int*)calloc(numsSize, sizeof(int));
int* q = (int*)calloc(numsSize, sizeof(int));
for (int i = 0; i < numsSize; i++)
{
int j;
for (j = 0; j < count; j++)
{
if (nums[i] == p[j])
{
break;
}
}
if (j == count)
{
p[count] = nums[i];
count++;
}
}
for (int i = 1; i <= numsSize; i++)
{
int j;
for (j = 0; j < count; j++)
{
if (i == p[j])
break;
}
if (j == count)
{
q[*returnSize] = i;
(*returnSize)++;
}
}
return q;
}
进阶:你能在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗?
你可以假定返回的数组不算在额外空间内。
思路:将数组元素的数据取绝对值减一后作为下标,因为数据的取值是[1,n],而数组下标的取值是[0,n-1]
将找到的元素,如果是正数,则置为负数,否则不变。
最后未出现负数的元素,下标加1就是在数组中未出现的数
例子:
[2, 3, 3, 2, 4] 注意数组10个元素,值为[1-10],
但是访问下标应该在[0-9]之内,因此修改位置下标应该是值-1
0号元素是2,则将1号位置置为对应负值 [2, -3, 3, 2, 4]
1号元素是3,则将2号位置置为对应负值 [2, -3, -3, 2, 4]
2号元素是-3,绝对值为3,将2号位置为负值,但是2号位已经重置过,不需要重置,
否则会变正数[2, -3, -3, 2, 4]
3号元素是-2,绝对值为2,将1号位置为负值,但是1号位已经重置过,不需要重置,
否则会变正数[2, -3, -3, 2, 4]
4号元素是4,则将3号位置置为对应负值 [2, -3, -3, -2, 4]
遍历数组得到0,4两个位置的数据是大于0的,因为人家数值从1开始,因此+1后得到1, 5两个缺失的数字。
int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize)
{
*returnSize = 0;
for (int i = 0; i < numsSize; i++)
{
int tmp;
if (nums[i] < 0)
{
tmp = -nums[i];
}
else
{
tmp = nums[i];
}
if (nums[tmp-1] > 0)
{
nums[tmp-1] *= -1;
}
}
int* p = (int*)calloc(numsSize, sizeof(int));
for (int i = 0; i < numsSize; i++)
{
if (nums[i] > 0)
{
p[*returnSize] = i + 1;
(*returnSize)++;
}
}
return p;
标准答案:
//标准答案
int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize) {
for (int i = 0; i < numsSize; i++) {
if (nums[abs(nums[i]) - 1] > 0)
nums[abs(nums[i]) - 1] = -(nums[abs(nums[i]) - 1]);
}
int* ret = (int*)malloc(sizeof(int) * (numsSize));
*returnSize = 0;
for (int i = 0; i < numsSize; i++) {
if (nums[i] > 0) {
ret[*returnSize] = i + 1;
*returnSize += 1;
}
}
return ret;
}
abs函数——头文件stdlib.h
int abs (int n);
用途:对一个整数取绝对值