二进制和位运算中的异或

1、给出一个问题:给你一个整形数组,这个数组中除了一个数字仅仅出现一次外,其它数字都仅仅出现两次,求出那个仅仅出现一次的数字?

要求:时间复杂度为O(n) , 空间复杂度为O(1)。

这个题目的难点在于空间复杂度的限制。

解法:一个数出现两个,两个数同样。而相等两个数异或的值为0 。 所以。我们仅仅须要把整个数组的数都异或一遍,我们就能得到仅仅出现了一次的那个数字

<span style="font-size:18px;">int get_one_num(int num[] , int n)
{
    int first = num[0] , i;
    for(i = 1; i < n; i++)
        first ^= num[i];
    return first;
}</span>

2、问题二:如今这个数组中,有两个数仅仅出现了一次。求出这两个数字,且时间、空间复杂度不变。

假设依据第一个问题的解法。我们最后面也是得到了一个值,但这个值是那两个数字(仅仅出现一次)的异或值。我们又不知道这个两个数字的不论什么一个。所以我们得不到这两个数字。

假设我们把数组切割成2个数组。每一个数组中仅仅含有一个仅仅出现一次的数字。再调用问题一的解法,我们就能得到结果。

关键在于我们怎么来切割这个数组,且空间复杂度是O(1)?

首先我们从头到尾依次异或数组中的每个数字,得到的结果就是两个仅仅出现一次数字的异或结果,由于这两个数字肯定不一样,所以得到的结果数字肯定不是0。也就是这个二进制数字钟至少有一位是1 。 我们在这个结果数字中华找到第一个为 1的位的位置,记为第n为。我们就通过第n位是不是1,一把这个数组切割成一个数组。

代码


<span style="font-size:18px;">int find_one(int x)
{
    int p = 1;
    while(true)
    {
        if((p^x) < x)  break;
        p <<= 1;
    }
    return p;
}

void get_one_num(int num , int n)
{
    int first = num[0] , i;
    for(i = 1; i < n; i++)
        first ^= num[i];
    int one = find_one(first);

    int x = 0 , y = 0;
    for(i = 0; i < n; i++)
    {
        if((one^num[i]) < num[i])
            x ^= num[i];
        else y ^= num[i];
    }

    cout<<(x<y?x:y)<<" "<<(x>y?x:y)<<endl;
}</span>
				
时间: 2024-12-15 01:59:50

二进制和位运算中的异或的相关文章

位运算中的异或运算

参与运算的两个值,如果两个相应的bit位相同,则结果为0,否则为1 char a1 = '十', a2 = '点', a3 = '进', a4 = '攻';            char secret = '8';            a1 = (char)(a1 ^ secret);            a2 = (char)(a2 ^ secret);            a3 = (char)(a3 ^ secret);            a4 = (char)(a4 ^ se

php位运算 与 或 异或 取反

<?php /** php中有4个位运算,分别是&与 |或 ^异或 ~取反 & 两位全为1,结果为1 | 有一位为1,结果为1 ^ 一个为0,一个为1,结果为1 ~ 取反0->1,1->0 1.二进制的最高位是符号位,0表示正数,1表示负数. 2.正数的原码,反码,补码都一样. 3.负数的反码=它的原码符号位不变,其它位取反(0->1,1->0). 4.负数的补码=它的反码+1. 5.0的反码,补码都是0. 6.php没有无符号数,换言之,php中的数都是有符

二进制的位运算

二进制的位运算: 1.按位与 & 1)清零.如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零. 2)取数中指定位.取对应x位,该数的对应位为1,其余位为零.可以得到x位的指定位数. 2.按位或  | 1)常用来对一个数的某个位,置1. 3.异或运算 ^ 1)使特定位翻转,对应X要翻转的各位,该数的对应位为1,其余位为零,此数与X对应位异或即可. 2)与0相异保留原值. 值交换的方法:1.借助第三变量来实现:C=A;A=B;B=C; 2.利用加减法实现两个变量

(九)二进制、位运算、位移运算符

JavaSE(九) --二进制.位运算.位移运算符 一.二进制简介 现代电子计算机全部采用的是二进制,因为它只使用0,1两个数字符号,简单方便.数字电路中,1代表高电平,2代表低电平.这样,数据的传输通过控制电平的高低就可以了.计算机内部处理信息,都是采用二进制数来表示的.二进制(Binary)数用0和1的两个数字及其组合来表示任何数,进位规则是"逢二进一",按从右至左的顺序,右低位,左高位. 二.二进制基础 1.所有的二进制数最高位代表符号位,0表示正数,1表示负数. 2.一个字节等

关于二进制以及位运算

聊到二进制以及位运算就不得不说说,原码,反码,补码了,网上对于原码反码补码的解释过于复杂,我这里把教程里的一些总结搬出来让大家参考一下:对于有符号的而言; 1.二进制最高位是符号位,0表示正数,1表示负数: 2.正数的原码反码补码都一样: 3.负数的反码等于它的原码符号位不变,其他位取反,1变0,0变1: 4.负数的补码等于它的反码+1: 5.0的反码补码都是0: 6.PHP没有无符号数: 7.在计算机运算时,都是以补码的方式来运算的: 所以当你进行位运算时,应把变量的补码求出后进行运算之后,再

二进制-高效位运算

数独 数独是介绍位运算的好例子,运用位运算和不运用效率差别还是挺大的.我们先看数独需求: 1.当前数字所在行数字均含1-9,不重复 2.当前数字所在列数字均含1-9,不重复 3.当前数字所在宫(即3x3的大格)数字均含1-9,不重复(宫,如下图每个粗线内是一个宫) . 常规算法 若是我们采用常规方式的,每填写一个数字,需要检查当前行.列,宫中其他位置是否有重复数字,极端情况下需要循环27(3*9)次来进行检查,我们看下常规算法下check int check(int sp) { // 檢查同行.

Java基础之二进制的位运算介绍

前言 Java编程思想中的操作符这个章节的第一句:在最底层,Java中的数据是通过使用操作符来做的.下面我将重点介绍位运算. 算术运算 Java语言中的基本算术操作符与其他的大多数的程序设计语言是相同的.其中包括 1.加,+ 2.减,- 3.乘,* 4.除,/ 5.取模, % 位运算 1.与 & 2.或 | 3.非 ~ 4.异或 ^ 5.左移 << 6.右移 >> 7.补零右移 >>> 参考资料 Java基本运算符 :https://www.cnblogs

POJ 2436 二进制枚举+位运算

题意:给出n头牛的得病的种类情况,一共有m种病,要求找出最多有K种病的牛的数目: 思路:二进制枚举(得病处为1,否则为0,比如得了2 1两种病,代号就是011(十进制就是3)),首先枚举出1的个数等于k的二进制数,然后跟所有的牛的代号一一比较,符合的           +1,找出其中和最大的:就是转换2进制麻烦,用位运算就好实现了,但是位运算不是很明白含义,明白了再补充: 知识点: 3 & 2 = 2,相同为1,不同为0, 011 & 010 = 010:(怎么利用的这个特点不明白):

位运算反(~)与(&amp;)异或(^)或(|)右移(&gt;&gt;)左移(&lt;&lt;)

先知道这两个二进制数据的特点:   1=0000 0000 0000 0000 0000 0000 0000 0001 -1=1000 0000 0000 0000 0000 0000 0000 0001 1.最高位(首位)表示正负(0为正,1为负) 2.最低位(末位)表示奇偶(0为偶,1为奇) 一.按位取反(~) 十进制1按位取反后=? 分析: 1. 十进制1转为二进制为:1= 0000 0000 0000 0000 0000 0000 0000 0001 2. 按位取反:把原来的二进制得到一