使用位操作

见朋友出了问题,最近访问技术论坛时,大致是这样的:有一组。其中包括:N整数,除了的整数只有一次以外,其他已经出现3二级。如何找到只出现一次最快的数?

作者的解法有点忘记了。可是这个题突然让我想起之前《编程之美》里的一道题, 和这个题的差别是其它都出现2次,仅仅有一个是出现一次。

它的解法很巧妙。就是把全部整数进行异或运算,最后的结果就是仅仅出现一次的那个整数。由于异或会把相同的消除掉。可是这个题是出现3次。异或已经解决不了。第一想法是空间换时间,全部数中取最大值Max,然后定义一个数组int hashArr[Max],运用hash的思想。遍历全部整数进行hashArr[i]++运算。最后再找出hashArr[i]为1的,下标值就是所求的数。这个解法相同适用于其它出现N次的情况。解法时间复杂度为O(N),空间额外开销为S(MAX)

可是我们能够继续深入分析。以32bit整数为例。假设把全部数的第i个比特位相加,假如和为sum。则会有例如以下等式:3(x1 + x2 + ... + xn) + x0 = sum (x1代表第一个数的第i个比特位的值 X0代表仅仅出现一次整数的第i个比特位的值) 从这个等式中能够看出x0的值为sum/3的余数。由于x0不是1就是0。肯定小于3。所以我们能够有例如以下的代码:

int arr[N] = {};
int _tmain(int argc, _TCHAR* argv[])
{
	int nMask = 1;
	int nBitSum = 0;
	int nDst = 0;
	for (int i = 0; i < 32; ++i)	//依次推断32位
	{
		for (int j = 0; j < N; ++j)	 //对N个数的第i位求和
		{
			if (arr[j] & nMask)
			{
				nBitSum++;
			}
		}

		if (nBitSum%3 != 0)		//余数不是1就是0
		{
			nDst |= nMask;
		}

		nMask <<= 1;
		nBitSum = 0;
	}

	return nDst;
}

这样就把仅仅出现一次的数求出来了,并且假设其它数出现的次数是M次的话,mod M就能够了。时间复杂度是O(32*N),  空间额外开销就是几个成员变量。

相比較而言还下面的算法是较好,当然,还详细介绍了情况而定。

版权声明:本文博主原创文章,博客,未经同意不得转载。

时间: 2024-07-29 22:12:00

使用位操作的相关文章

c语言的位操作

c语言的位操作最常用的地方就是用在对寄存器的写值上. 一.基本的一些概念 1.位与:& 操作:1 & 1 = 1: 1 & 0 = 0: 0 & 0 = 0: 特点:只有全是1的时候才是1,其他情况都是0. 总结:任何数和0位与就是0,和1位与没有变化,所以位与常用在清零上(清零用位与). 2.位或:| 操作:1 | 1 = 1: 1 | 0 = 1: 0 | 0 = 0: 特点:只有全0的时候才是0,其他情况都是1. 总结:任何数和1位或就是1,和0位或没有变化,所以位或

位操作的技巧

一,基本概念认知 1,为啥要用补码 计算机中的符号数有三种表示方法,即原码.反码和补码.三种表示方法均有符号位和数值位两部分,符号位都是用0表示"正",用1表示"负",而数值位,三种表示方法各不相同. 在计算机系统中,数值一律用补码来表示和存储.原因在于,使用补码,可以将符号位和数值域统一处理:同时,加法和减法也可以统一处理.此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路.(来自百度百科) 2,补码的求法: 正数的补码和原码相同: 负数是对应正数

C/C++位操作

异或:不同为1,相同为0.可以记为:"异"为不同,不同为1. C方式位操作总结: 设置特定的位用|; 清除特定的位用&; 取反特定的位用; 取反所有的位用~; 引用自

在32位、64位操作系统下各数据类型所占的字节数

点击打开链接 在32位.64位系统当中,唯一改变的是指针的长度;在32位系统当中是4个字节.64位则是8个字节.所谓的32位.64位,这个指的是寄存器的位宽. 32位平台下结果: 64位平台下结果: 一.下面几点是值得大家注意的: 1.关于 int 的取值范围,缺省的int数值范围是由编译器设计者决定的,通常都是机器最为自然高效的位数.甚至,我们在32位的机器上,前提没有什么指令可以高效的的处理更短的整型值,我们可以将short.int.long都设置成32位. 2.浮点数在缺省的情况下 表示的

关于java按位操作运算

<1>.在了解位移之前,先了解一下正数和负数的二进制表示形式以及关系:举例15和-15: 15 的原码: 00000000 00000000 00000000 00001111     补码: 11111111 11111111 11111111 11110000                 +1 = -15的原码:11111111 11111111 11111111 11110001 负数的原码即为:正数的原码取反,再加1. <2>位移操作:(只针对 int类型的数据有效,j

MySQL学习2:Windows 64位操作系统下安装和配置MySQL

一安装方式 MySQL安装文件分为两种,一种是MSI格式的,一种是ZIP格式的.下面来看看这两种方式: MSI格式的可以直接点击安装,按照它给出的安装提示进行安装,Windows操作系统下一般MySQL将会安 装在C:\Program Files\MySQL该目录中. ZIP格式是自己解压,解压缩之后其实MySQL就可以使用了,但是要进行配置.这个可以在网上随便找,给出很 多自定义安装和配置的详细步骤.推荐的链接:http://jingyan.baidu.com/article/f79b7cb3

netty中的位操作

看了PoolChunk源码,好多位操作,对这些位操作理解不到位,看起来很是吃力,不知道为什么要这么做,但是是性能更好 1:大小为2 的冥的数加1 怎么操作 size^1; 2: <=比较   mask=~(pageSize-1) num & mask  !=0   那么num <mask 4:两个数互补 mask= -(constNum) mask & num==0

位操作的一些常用用法

参考: 位操作基础篇之位操作全面总结 位操作有6种基本操作符,按照优先级分别是: 取反   - 移位   <<  >> 与      & 异或   ^ 或      | 常用的用法有: 1 判断偶数,判断最低位是0还是1即可,比求模快 1 x % 2 != 0 //x正负都可以判断:不用x%2 == 1,因为如果x为负奇数,x%2=-1 2 x & 0x1 == 0 2 交换两个数,不用中间变量 1 void mySwap(int &a, int &

c语言中的位移位操作

先要了解一下C语言里全部的位运算都是指二进制数的位运算.即使输入的是十进制的数,在内存中也是存储为二进制形式. “<<”使用方法: 格式是:a<<m,a和m必须是整型表达式,要求m>=0. 功能:将整型数a按二进制位向左移动m位,高位移出后,低位补0. “>>”使用方法: 格式是:a>>m,a和m必须是整型表达式,要求m>=0. 功能:将整型数a按二进制位向右移动m位,低位移出后,高位补0 C语言中的移位操作,内容不多.只是有些地方你不注意,就疏

【C语言天天练(二二)】位操作

C的位运算符 1.二进制反码或按位取反:~ ~(10011010) = (01100101). 假设val是一个unsigned char,~val不改名原来val的值. 2.位与:& 二进制运算符&通过对两个操作数逐位进行比较产生一个新值. (10010011)&(00111101)=(00010001). C中的一个组合的位与赋值运算符:&=. 3.位或:| 二进制运算符|通过对两个操作数逐位进行比较产生一个新值. (10010011)|(00111101)=(1011