我是靠谱客的博主 留胡子蛋挞,最近开发中收集的这篇文章主要介绍【剑指Offer】数组中只出现一次的两个数字(其余数都出现两次)(普通排序 / 满足交换律的异或)题目描述解法,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
目录
- 题目描述
- 解法
- 排序然后左右比较
- 满足交换律的异或
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
解法
排序然后左右比较
- 先将数组升序排序。
- 从第一个数开始,比较相邻两个数字xi,xi+1:如果相同,则往后移两位,继续比较;如果不同,则判断xi和前面数字是否也不同,xi+1和后面数字是否也不同,这样判断它数值的唯一性。
- 需要注意最后一个数字没参与比较,所以如果结果还差一个数,那就是差的最后这个数字。
- 时间复杂度O(NlogN):N是数组大小,因为vector容器的排序是快排,最好、正常和平均时间复杂度都为O(nlogn),后面查找是O(N)
- 空间复杂度O(1)
【牛客】
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
sort(data.begin(), data.end());
int size = data.size();
bool findflag1 = false, findflag2 = false;
int i = 0;
while( i<=size-2 && (!findflag1 || !findflag2) ){
if( data[i] == data[i+1] ){
i += 2;
continue;
}
int j = i;
//data[i]和前面的数组比较,如果不相同,说明data[i]不等于后面也不等于前面,是个特数
if( i==0 || (i>=1 && data[i-1]!=data[i]) ){
if( !findflag1 ){
*num1 = data[i];
findflag1 = true;
j++;
}else if( !findflag2 ) {
*num2 = data[i];
findflag2 = true;
j++;
}
}
//data[i+1]和后面的数组比较,如果不相同,说明data[i+1]不等于前面也不等于后面,是个特数
if( i==(size-2) || (i <= size-3 && data[i+1] != data[i+2]) ){
if( !findflag1 ){
*num1 = data[i+1];
findflag1 = true;
j++;
}else if( !findflag2 ) {
*num2 = data[i+1];
findflag2 = true;
j++;
}
}
i = j;
}
//最后一个数
if( !findflag1 ){
*num1 = data[size-1];
findflag1 = true;
}
if( !findflag2 ){
*num2 = data[size-1];
findflag2 = true;
}
}
};
【leetcode】
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
vector<int> anws;
sort(nums.begin(), nums.end());
int size = nums.size();
int i = 0;
while( i<=size-2 && ( anws.size()<2 ) ){
if( nums[i] == nums[i+1] ){
i += 2;
continue;
}
int j = i;
//nums[i]和前面的数组比较,如果不相同,说明nums[i]不等于后面也不等于前面,是个特数
if( i==0 || (i>=1 && nums[i-1]!=nums[i]) ){
anws.push_back(nums[i]);
j++;
}
//nums[i+1]和后面的数组比较,如果不相同,说明nums[i+1]不等于前面也不等于后面,是个特数
if( i==(size-2) || (i <= size-3 && nums[i+1] != nums[i+2]) ){
anws.push_back(nums[i+1]);
j++;
}
i = j;
}
//最后一个数
if( anws.size()<2 ){
anws.push_back(nums[size-1]);
}
return anws;
}
};
满足交换律的异或
参考了leetcode讨论区某个高赞回答
- 对所有数字进行异或操作:因为异或满足交换率,相同的数都异或为0抵消了,剩下两个独数,所以异或结果其实是两个独数的异或结果。异或结果肯定有某一位为1,不然都是0的话就是相同数(两个独数一个在此位为0,另一个为1)。
- 找到这个位(随便哪一位都可以)并设为mask:从最低位0001开始,如果和异或结果的相与结果为0,那就不断左移,往更高位0010找
- 按此位将所有数分成两组:用mask来对所有数相与,根据与结果是否为0来将数分为两组
- 分成两组后,组内所有数各自异或:相同的两个数异或肯定为0(而且分开的时候,相同的两个数必为一组),最后剩下的每组里就是我们要找的独数。
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
//XOR是所有数字的异或结果:
//因为异或具有交换性,相同的数都异或为0了,所以这个结果其实是两个独数的异或结果,
int XOR = 0;
for( int i = 0; i < data.size(); i++ ){
XOR ^= data[i];
}
//XOR一定不为0,被置1的位表示在这一位上两个独数是不同的(在这位上一个为0,另一个为1)
//找出这一位(随便哪一位都可以)并设为mask
int mask = 1; //从最低位开始
while( (XOR & mask) == 0 ){
mask <<= 1; //左移,继续往更高位找
}
//用mask来对所有数相与,可以根据结果是否为0将数分为两组,并且组内所有数的异或结果就是独数
int group1 = 0, group2 = 0;
for( int i = 0; i < data.size(); i++ ){
if( (data[i] & mask) == 0 ){ //异或结果为0的组
group1 ^= data[i]; //组内所有数进行异或操作,最后的异或结果只剩独数
}else{//异或结果为1的组
group2 ^= data[i];
}
}
*num1 = group1;
*num2 = group2;
}
};
最后
以上就是留胡子蛋挞为你收集整理的【剑指Offer】数组中只出现一次的两个数字(其余数都出现两次)(普通排序 / 满足交换律的异或)题目描述解法的全部内容,希望文章能够帮你解决【剑指Offer】数组中只出现一次的两个数字(其余数都出现两次)(普通排序 / 满足交换律的异或)题目描述解法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复