题目描述
首先一开始 我是怎么做的呢?
我利用for循环遍历 写了一大堆,重复测试,最后终于写好了 我开始运行;结果我运行的时候 他告诉我
我超出时间限制
我giao,我真的会谢。
int* findErrorNums(int* nums, int numsSize, int* returnSize){
int i = 0;
int* num_s = malloc(sizeof(int)*2);
int loss = 0;
int loss_1 = 0;
*returnSize = 2;
int flag = 0;
int j = 0;
for(i = 0;i < numsSize;i++)
{
for(j = 0;j<numsSize-i-1;j++)
{
int tmp = 0;
if(nums[j]>nums[j+1])
{
tmp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = tmp;
}
}
}
for(i = 0;i<numsSize;i++)
{
for(j = 0;(j<numsSize&&i!=j);j++)
{
if(flag == 0)
{
if(nums[i] == nums[j])
{
loss = nums[j];
flag = 1;
}
}
}
}
int t = 0;
for(i = 0;i<numsSize;i++)
{
t++;
if(nums[0] != 1)
{
loss_1 = 1;
}
else
{
if(nums[i] != t)
{
loss_1 = t;
if(loss>loss_1)
{
break;
}
}
}
}
num_s[0] = loss;
num_s[1] = loss_1;
return num_s;
}
以上仅供娱乐;
下面是正解;
int* findErrorNums(int* nums, int numsSize, int* returnSize){
int i = 0;
int* num_s = malloc(sizeof(int)*2);
int loss = 0;
*returnSize = 2;
int j = 0;
for(i = 0;i < numsSize;i++)
{
for(j = 0;j<numsSize-i-1;j++)
{
int tmp = 0;
if(nums[j]>nums[j+1])
{
tmp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = tmp;
}
}
}
int tmp = 0;
for(i = 0;i<numsSize;i++)
{
tmp = nums[i];
if(tmp == loss)
{
num_s[0] = loss;
}
else if(tmp - loss>1)
{
num_s[1] = loss+1;
}
loss = tmp;
}
if(nums[numsSize-1] != numsSize)
{
num_s[1] = numsSize;
}
return num_s;
}
这只是一种解法
还有一个 位运算的方法
提到运算符,我们要先熟悉掌握 位操作符的使用
& 按位与 | 按位或 ^ 按位异或 (注:他们的操作数必须是整数。)
1.按位与
int main()
{
int a = 3;
int b = -5;
int c = a & b;
printf("c = %d\n", c);
return 0;
}
思考一下,C会等于多少呢?
结果是 C = 3
3 的原 反 补码 (正数的原反补码相同)
00000000000000000000000000000011
-5的原码
10000000000000000000000000000101 -5的原码
11111111111111111111111111111010 -5的反码
11111111111111111111111111111011 -5的补码
00000000000000000000000000000011 3的补码
& 按位与 表示 2 进制位 相同位都为 为一 不同位(都是零也为零)为零 那么计算结果 为
00000000000000000000000000000011 为 3
所以C = 3;
2.按位或
int main()
{
int a = 3;
int b = -5;
int c = a | b;
printf("c = %d\n", c);
return 0;
}
再思考:
11111111111111111111111111111011 -5的补码
00000000000000000000000000000011 3的补码
| 按位或 表示 2 进制位 一位为一 就为一 两个都是零 才为零;11111111111111111111111111111011 (-5的补码)
3.按位异或
int main()
{
int a = 3;
int b = -5;
int c = a ^ b;
printf("c = %d\n", c);
return 0;
}
11111111111111111111111111111011 - 5的补码
00000000000000000000000000000011 3的补码
^ 按位或 表示 2 进制位 相同为零 相异为一;
11111111111111111111111111111000(-8的补码)
以上都是 这些为位运算符的基本使用规则; 下面来说一次 他们的简单性质(遵循交换律和结和律)
a^a = 0
0^a = a
a^b^a = b
掌握了这些,现在我们可以来对一开始的题目进行分析求解;
通过分析我们可以知道:
重复的数字在数组中出现 2 次,丢失的数字在数组中出现 0 次,其余的每个数字在数组中出现 1 次。由此可见,重复的数字和丢失的数字的出现次数的奇偶性相同,且和其余的每个数字的出现次数的奇偶性不同。如果在数组的 n 个数字后面再添加从 1 到 n 的每个数字,得到 2n 个数字,则在 2n 个数字中,重复的数字出现 3 次,丢失的数字出现 1 次,其余的每个数字出现 2 次。根据出现次数的奇偶性,可以使用异或运算求解。
代码 如下
int* findErrorNums(int* nums, int numsSize, int* returnSize) {
int* errorNums = malloc(sizeof(int) * 2);
int xorSum = 0;
for (int i = 1; i <= numsSize; i++)
{
xorSum ^= i; //增加一组(1->n)的数据
xorSum ^= nums[i - 1]; //for 循环结束 这里xorSum 的结果应该就是
//重复数字 ^ 缺失数字
}
int lowbit = xorSum & (-xorSum);//我们知道 负数与正数 的区别是
//负数的补码是正数按位取反 加一得到的
//所以 这里lowbit就为xorSum的最低位;
//而 xorSum = 重复数字 ^ 缺失数字
//也就是说 lowbit 就是 重复数字和缺失数字最低的不同位
//利用lowbit可以将数组分成两组
//第一组的每个数字 a都满足 a & lowbit==0,
//第二组的每个数字 b都满足 b & lowbit!=0
int num1 = 0, num2 = 0;
for (int i = 0; i < numsSize; i++)
{
if ((nums[i] & lowbit) == 0)
{
num1 ^= nums[i];
} else {
num2 ^= nums[i];
}
}
for (int i = 1; i <= numsSize; i++)
{
if ((i & lowbit) == 0)
{
num1 ^= i;
} else {
num2 ^= i;
}
}
int* ret = malloc(sizeof(int) * 2);
*returnSize = 2;
for (int i = 0; i < numsSize; i++)
{
if (nums[i] == num1)
{
ret[0] = num1, ret[1] = num2;
return ret;
}
}
ret[0] = num2, ret[1] = num1;
return ret;
}
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/set-mismatch/solution/cuo-wu-de-ji-he-by-leetcode-
下面我们来看一下标准答案
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/set-mismatch/solution/cuo-wu-de-ji-he-by-leetcode-solution-1ea4/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。