[go] go中的位运算

背景

今天做每日一题的时候,发现这个每日一题之前好像做过,看看题号还有提交记录,感觉应该是之前某场周赛做过的题目 话说好久没做周赛了 23333

结果自信一跑,发现测试样例一直有一个没通过,开始怀疑算法和题目,最后的最后发现,忽略了题目中的条件 :nu:

目标数组首先长度是偶数

哦,那鲁ho多,于是我果断把数组长度 * 2 再 /2,一提交,果然A了 :ku: :ok:

然后我又想,这样乘二除二是在是不够优雅,有无直接把最后一位给抹掉的方式,最好也不要加if语句去判断

然后我隐隐约约想到了go的一个很冷的运算符,&^,没错,是由与运算符和异或运算符拼一起的一个出场率极低的运算符,它的作用就是按位置0

7 &^ 1 = 6 // 111 &^ 001 = 110
7 &^ 2 = 5 // 111 &^ 010 = 101
7 &^ 4 = 3 // 111 &^ 100 = 011

a &^ b = c,如果b中对应位是1,则将a中对应位给置为0

那么我又好奇,是不是单独依靠与,或,异或无法一次做到上述的需求?试了半天,好像确实不行

那话又说回来,按位置零这个操作是咋实现的呢,用到&^是不是就是靠这两种操作顺序进行得到的,于是我试了一下

package main

import "fmt"

func main() {

    a := 7
    b := 4

    fmt.Println(a &^ b)      // 3
    fmt.Println((a ^ b) & a) // 3

    
}

看来确实如我所设想的一样,a和b异或的结果就是b位为1在a中的对应位,如果是1则置0,如果为0则变为1,后再和a进行与,保证原来为0的位还是0即可

场景

那既然说到了位运算,那就简单总结一下之前遇到过的常见的位运算的操作

一般涉及到位,要么是二进制的数学运算,用么就是借由位进行统计

像bitmap也是用来用位进行统计

左移右移

  • 1. 快速乘2或者除2

异或

  • 1. 交换两个数
  • 2. 支持交换律与结合律

常见题目

1. 统计字符串中的字符是不是都只出现过一次

这是秋招时候华为考到的一道题

我的思路主要是考虑字符串中字符的类型和范围,如果是覆盖整个ASCII码(0-127),那用两个uint64整型的所有位进行统计,最后再看位1的个数是否和字符串的长度一致

优化思路:哈希表 -> 切片 -> 数组 -> 变量+位运算

2. 不使用算术运算符'+'实现加法操作

这是当时在某个刷题网站上看到的第一题,当时看题目以为是真正的两数之和,结果看到进阶要求,整个人虎躯一震,竟然还有这种操作 :jingku:

后面自己尝试着做了出来,发现脑海中当年学计组时候,ALU那章节的记忆隐隐约约浮现了出来 :huaji14:

3. 位1个数

就是通过位运算快速得到某个数字,它在二进制下有多少个位是1

好像和lowBit算法(用于获取一个数从右往左第一个位为1对应的值)有关,不过一般循环用x & (x - 1)直到x为0,记录循环次数

4. 只出现一次的数字

秋招被考到过的一题,也算是热门题了,即在一个数组中,除了某个数字,其它的数字都出现了两次,请找出这个数字

扩展的话,就是数组中有个数字只出现了1次,其它数字都出现了三次

主要是用到了异或的性质

5. 快速幂

和数位的权重相关

参考链接

位运算的奇技淫巧

点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注