2021 后端开发笔记 20 异或运算算法题

首先让我们来看看什么是异或运算

异或运算:相同为0不同为1
同或运算:相同为1不同为0

同时我们还需要知道异或运算的性质
1. 0 ^ N == N
2. N ^ N == 0
这两个性质非常重要哦!待会会频繁用到

接下来我们从题目开始:

题目1:

如何不用额外变量交换两个数?

大家都知道在Python中是不需要的,那么如果在Java中我们就需要使用额外的一个变量先去记录一个值,然后再去交换。
像是这样: int a = 10;, int b = 5;,我们就需要先用一个临时变量记录其中一个值, 例如:
int temp = a; 然后再去交换 a = b, b = temp 这样我们的交换就完成了。

但是这需要用到额外变量,那么我们如何不适用额外变量就能替换两个值呢?我们就需要用到异或了 。
根据异或的性质,N 异或 N == 0,所以我们可以 用 a 异或 a 然后再异或 b,a是不是就变成了b呢?

让我们来看看代码实现,其实就是这么简单的几行代码,我们用a来替代了额外变量,第二行就相当于a ^ b ^ b我们就得到了a,然后让b接收了这个 变量我们就进行了交换。然后再用新的b也就是a,异或 a ^ b,也就是 a ^ b ^ a,得到了b。这样我们就完成了交换

a = a^b;
b = a^b;
a = a^b;
题目2:

一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数字?

我们同样也可以用到之前的异或的性质,两个相同的数字如果异或一定为0,所以我们只要将所有的数字异或,我们就能得到出现了奇数次的数字。

让我们来看代码:
申请一个变量接收异或的结果,然后循环数组中所有数字,和额外变量异或,最后返回结果就行了

public class QuestionTwo {
    public static int oddTimeNum(int[] arr){
        int eor = 0;
        for(int num: arr){
            eor ^= num;

        }
        return eor;
    }
}
题目3:

如何把一个int类型的数,提取出二进制形式最右侧的1来?
提取最右侧的数字我们只要 !!!把这个数字和它的负数做相位与就好了

我们先来说说在二进制里面一个负数是怎么表示的,首先将这个数上的所有位取反然后+1
例如数字3:二进制表示是011,负数就是取反100,然后+1,就是101
然后我们再将 3 和 -3做相位与 011 & 101,答案就是001这样我们就提取出来最右侧的1了。

前面都是我缩短了之后实际上在计算机里面的状态是

0000 0000 0000 0000 0000 0000 0000 0011 (这个表示3)

1111 1111 1111 1111 1111 1111 1111 1100 (这个是反码)

1111 1111 1111 1111 1111 1111 1111 1101 (+1变成 - 3)

0000 0000 0000 0000 0000 0000 0000 0001(和原来的3与完之后)

代码只有两行

int a = 3;
int rightOne = a & (-a); 
题目4:

题目2的升级版,如果有两个数出现了奇数次,其他数字出现了偶数次,怎么找到这两个奇数,并且打印出来?

听起来很难?其实思路也是利用异或的性质。

  1. 我们先将所有数字异或,这样我们就能得到a 异或 b(因为出一个数字偶数次异或都为0)。

  2. 然后我们在提取出a异或b的二进制上的任何一个1,为什么要这样做?因为只有a或者b上有1那一位才有1,所以我们拿着这个1和原数组中这个位置上有1的进行异或,我们是不是就能把其中一个数字提取出来?

  3. 然后我们再将这个数字和a异或b去异或,这样我们就能拿出另个一数字。

为了方便我们取a异或b最右边的1,上面那题已经说过了,我们将a异或b用变量eor来表示,就是eor逻辑与上-c

接下来我们来看代码:

public static void OddTimeNum(int[] arr){
        // 用来存储数组中所有数字都被异或了的结果
        int eor = 0;
        for(int num : arr){
            eor ^= num;
        }
        // 提取最右侧的1
        int rightOne = eor & (-eor);
        
        // 存储其中一个数字
        int oneOfTwo = 0;
        for(int num : arr){
            // 如果这个数字上那个位置有1,就不是我们想找的
            if((num & rightOne) != 0){
                oneOfTwo ^= num;
            }
        }
        System.out.println(oneOfTwo);
        System.out.println(eor ^ oneOfTwo);
    }

Reference: https://italk.mashibing.com/course/detail/cour_00004003

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容