leetcode刷题day1
Posted 我是晓伍
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode刷题day1相关的知识,希望对你有一定的参考价值。
此题来源于剑指offer 56 - 1.数组中数字出现的次数
题目如下:
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
限制:
2 <= nums.length <= 10000
思路:
这道题我用的是异或的方法写的,我们先把数组的每一个元素一起异或一遍
这之后我们思考操作后会得到什么,首先要肯定的是:
1.0和任何数异或都为任何数本身。
2.异或具有交换律。
3.两个相同的数异或后为0。
有了这三个武器以后,我们分析起来就好多了。
首先,把成对的数放在一起异或(只是分析,实际操作还是按数组顺序异或,因为交换律才能改顺序分析)
根据武器3,这样得出来的结果是一堆0异或。
而根据武器1,我们可以把这个结果分析到剩下一个0,和两个不成对的数–也就是两个目标数异或。
所以我们对数组每个元素进行异或后得到的结果就是两个目标元素异或出来的值
那么接下来就是得考虑这两个数要怎么从异或状态分开,或者说怎么找到这两个数。
我们先假设target1为1,target2为2
那么有
思路是:先找到两数异或的结果中的二进制位数为1的位。
比如
这个1代表着target1的这一位和target2的这一位是不相同的
接下来对原数组元素进行分类,如果数组元素中这一位是1的分一类,不是1的分一类。
那么,成对的元素依旧不会被分开,因为它们之间的二进制位完全相同,而1于6由于这一位不同的原因会被分到两边。
接下来,我们只要对两边元素分别做异或,那就能分别得到两个数了。
代码实现
int *singleNumbers(int *nums, int numsSize, int *returnSize)
int tmp1 = 0;
int tmp2 = 0;
int i = 0;
for (i = 0; i < numsSize; i++)
tmp1 = tmp1 ^ nums[i];
//tmp1现在就是两个目标数的异或结果
int digit = 1; //假设第一位就是1
//如果右移k位不是1,k从0开始,则位数加一,这样去找到位1的二进制位数
while (((tmp1 >> (digit - 1)) & 1) == 0)
digit++;
//查找k为为1的并异或
//初始化tmp1和tmp2为0准备用来得到两个target
tmp1 = 0;
tmp2 = 0;
//对原数组中的数分类并且做异或 处理
for (i = 0; i < numsSize; i++)
// digit的值代表第k位为1,所以要左移digit-1位去判断
if (((nums[i] >> (digit - 1)) & 1) == 1)
tmp1 = tmp1 ^ nums[i];
else
tmp2 = tmp2 ^ nums[i];
// 返回结果
*returnSize = 2;
int *space = (int *)malloc(2 * sizeof(int));
space[0] = tmp1;
space[1] = tmp2;
return space;
分析
函数第一次遍历数组进行异或操作用n个时间单元,
找第k位为1用了常数个时间单元,
接下来循环分类用了n个时间单元,
时间复杂度为O(n),符合题目要求。
由于创建的变量都为常数个,所以符合空间复杂度为O(1)的要求。
以上是关于leetcode刷题day1的主要内容,如果未能解决你的问题,请参考以下文章