称号:输入一个整数数组,除了两个数的阵列出现一次以外,现在的时间是其他人物出现2次要,求两个数字。
它需要的时间复杂度O(n),空间复杂度O(1)
1 题目要求时间复杂度为O(n)而且空间复杂度为O(1)。这个时候朴素的方法利用数字来记录出现次数的方案都是不行的。
2 依据题目的特点,仅仅有两个数出现一次,其他的全部数据都是出现2次。假设这两个数是a和b,那么对这个数组异或的结果就是a^b。如今我们就是要考虑怎么把数组分成两部分,一部分含有a。一部分含有b,则每部分异或的结果即为两个数a和b的值
3 由于a肯定不等于b。所以a^b的结果肯定不会等于0,那么我们能够就去这个异或结果中最右边的第一个1的位置,依据这个位置来划分这个数组。这个位置是1的位一部分。不是1的分为一部分。
4 比如数组{2,4,3,6,3,2,5,5},数组异或的结果为2,二进制位0010最右边1的位置为第二位。
则我们把数组分成两部分{2,3,6,3,2}中每一个数的二进制最右边第二位为1,剩下一部分{4,5,5}中每一个数二进制最右边第二位为0。
5 求出两部分之后我们就能够直接对每部分求异或就可以求出两个数的值
//找到两个仅仅出现一次的数 void FindNumAppearOnce(int *arrNum, int n){ //空指针和个数小于2都是不合法的数据 if(arrNum == NULL || n < 2){ return; } //先求出总的异或的值 int sum = 0; for(int i = 0; i < n; i++){ sum ^= arrNum[i]; } //找到sum的右边第一个1的位置 int pos = 0; while((sum & 1) != 1 && (pos <= 32)){ pos++; sum >>= 1; } //没有找出第一个1的位置 if((pos == 0) || (pos > 32)){ return; } //定义两个数为 int numOne = 0; int numTwo = 0; //枚举求出 int num = 1<<pos; cout<<num<<endl; for(int i = 0; i < n; i++){ if((arrNum[i]&num) != 0){ numOne ^= arrNum[i]; } else{ numTwo ^= arrNum[i]; } } cout<<numOne<<" "<<numTwo<<endl; }
版权声明:本文博客原创文章,博客,未经同意,不得转载。