剑指 Offer 56 - I. 数组中数字出现的次数
Posted 是小陳同学呀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指 Offer 56 - I. 数组中数字出现的次数相关的知识,希望对你有一定的参考价值。
理想的人物不仅要在物质需要的满足上,还要在精神旨趣的满足上得到表现。 —— 黑格尔
目录
题目:
一个整型数组 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]
做题链接:剑指 Offer 56 - I. 数组中数字出现的次数
方法1:排序+指针
假如数组中的数字是:1,2,10,4,1,4,3,3。我们将这些数字进行排序,排序之后为1,1,2,3,3,4,4,10。我们的目标就是找出没有重复出现的两个数字,也就是2和10。
我们使用一个指针指向排序好数组的最后一个位置。
1.然后看这个位置的数字和前一个位置的数字相不相等。如果相等,也就是没有找到我们的目标数字,然后指针向前移动两个位置,继续找,以此类推。
2.如果最后一个位置和前一个位置不相等,那么此时的最后一个位置也就是我们找到的第一个目标数字。然后指针向前移动一位,继续找前面的数字。
那么上述的话是什么意思呢?我们使用画图来理解。
理解上述的话之后,我们直接上手写代码:
#include<stdlib.h>
int cmp_int(void* p1, void* p2)
return *(int*)p1 - *(int*)p2;
int main()
int arr[10] = 0 ;
int n = 0;
scanf("%d", &n);
int i = 0;
for (i = 0; i < n; i++)
scanf("%d", &arr[i]);
qsort(arr, n, sizeof(int), cmp_int);//这里使用快排的进行排序
int right = n - 1;
int j = 0;
int k = 0;
while (right > 0)
if (arr[right] != arr[right - 1])
//这里不相等,则找到了,直接打印出来
printf("%d ", arr[right]);
if (right == 1)
printf("%d", arr[0]);
right -= 1;//所以right-1,指向下一个位置
else
right -= 2;//否则right-2,指向下两个位置
return 0;
if (right == 1)
printf("%d", arr[0]);
这个代码如何理解呢?我们举个例子来讲解一下。
如果我们排序好的数组是 1 ,2,5,5,7,7,9,9。那么我们要找的数字就是1和2, 此时right指向的就是2,然后2和前面的1比较,显然2和1不相等,那么2就是我们要找到的数字。
然后right向前移动一位,指向1,然后1再和前面的数字进行比较,但是1前面没数字了,那么退出循环。但是1没有打印出来呀,所以我们单独打印第一个数字。这就是这个代码的意思。
方法2:异或整个数组
异或的计算法则是:二进制相同为0,不同为1。
有一个找单身狗的题:数组中其他数字均出现两次,有一个数字出现了一次,我们的目标就是找这个出现一次的数字,我们就可以使用异或全部的数字,得到的答案就是我们要找的数字,因为相同的数字异或为0,0和目标数字异或得到目标数字。
做题方法:这题我们一样可以使用异或整个数组来实现。相同的数字异或为0,最后的异或结果就是两个目标数字异或的结果。假如数组为1,2,10,4,1,4,3,3。
废话不多说,直接上代码:
int* singleNumbers(int* nums, int numsSize, int* returnSize)
int* ans = (int*)calloc(2, sizeof(int));//calloc开辟的空间会自动赋值为0
int temp = 0;
int i = 0;
for (i = 0; i < numsSize; i++)
temp ^= nums[i];//temp就是两个目标数字异或的结果
int pos = 0;//记录位置
for (i = 0; i < 32; i++)
if (((temp >> i) & 1) == 1)//找二进制第一个1的位置
pos = i;
break;
//分组异或
for (i = 0; i < numsSize; i++)
if (((nums[i] >> pos) & 1) == 1)
ans[0] ^= nums[i];
else
ans[1] ^= nums[i];
*returnSize = 2;
return ans;
希望能对你有所帮助,感谢你的支持。
剑指Offer56 - I. 数组中数字出现的次数(位运算)
一个整型数组 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 <= 10000
思路:
1.先将数组中的全部数异或,最后得到的xor,就是num1和num2异或的结果
2.使用lowbit方法,获取xor最右边为1的数字,记作mask
3.再对数组进行一次遍历,因为num1和num2不相同,因此根据与运算mask的结果进行分流,最终两个数会被分流到不同的位置。
以实例2为例
代码
class Solution {
public int[] singleNumbers(int[] nums) {
int xor = 0;
for(int num : nums) xor ^= num; //全部数据异或的结果 = 数1和数2异或结果
//因为两个数不同,所以一定会有一位是1
int mask = 0;
mask = xor & (-xor); //xor最右的1
//此时获取的1用来区分数1数2
int[] ans = new int[2];
for(int num : nums){
//分流
if((num & mask) == 0) ans[0] ^= num;
else ans[1] ^= num;
}
return ans;
}
}
以上是关于剑指 Offer 56 - I. 数组中数字出现的次数的主要内容,如果未能解决你的问题,请参考以下文章
1787. 使所有区间的异或结果为零 / 剑指Offer56 - I. 数组中数字出现的次数 / 剑指Offer56 - II. 数组中数字出现的次数 II / 剑指Offer57.和为s的两个数字(
剑指Offer56 - I. 数组中数字出现的次数(位运算)
算法剑指 Offer 56 - I. 数组中数字出现的次数 重刷太难了