力扣每日一题之位运算的应用

给你一个字符串 s ,将该字符串中的大写字母转换成相同的小写字母,返回新的字符串。

当然我们可以用库函数解决这个问题,但是如果这个问题出现在面试里,那肯定是不能用库函数的。

这里我们使用位运算解决这个大小写转换问题。

我们知道

  1. 大写字母A-Z的ASCII码是65到90,小写字母的ASCII码是97到112,大小写字母的ASCII码相差32;

  2. 大写A(65)的二进制编码为1000001,小写a(97)的二进制编码位1100001

从上面我们可以发现一个规律:

  • 大小写是由第五位是1还是0来区分的。
1
2
3
4
5
6
func main() {
fmt.Println('a') // 97, 1100001
fmt.Println('z') // 122, 1111010
fmt.Println('A') // 65, 1000001
fmt.Println('Z') // 90, 1011010
}

问题转化为:如何让一个二进制的某一位的值发生改变?

  • 如果需要从0变成1,只需要和这个二进制数进行按位或运算,其中需要变化的位是1,其他位是0;
  • 如果需要从1变成0,只需要和这个二进制数进行按位与运算,其中需要变化的位是0,其他位是1;

大写转小写

在本题中,将二进制数的第5位从0变成1,那么只需要将该二进制数和二进制数0100000按位或即可:

而当该字母本身就是小写字母时,则二进制数不发生改变,即小写字母还是原来的小写字母

而二进制数00100000转换后得到十进制数32,因此如果需要将大写字母转换成小写字母,同时小写字母不变,只需要把这个字符按位或32即可:

1
2
b := 'A'
b |= 32 // 'a'

小写转大写

如果需要将小写转换成大写字母,需要将小写字母的二进制编码的第五位从1变成0,则需要将二进制数和二进制数11011111按位与即可。

而当该字母本身就是大写字母时,则二进制数不发生改变,即大写字母还是原来的大写字母

如何将110111111转换成十进制数呢?

二进制中最高位表示符号位,最高位是1时是负数,0是负数。

负数的计算方式:

1
-64+16+8+4+2+1 = -33

如果需要将小写字母转换成大写字母,同时大写字母不变,只需要把这个字符按位与-33即可:

1
2
b := 'A'
b &= -33

大写转小写,小写转大写

也就是二进制的第5位1变为0,同时0变为1.

小写转大写:

大写转小写:

将00100000转换成十进制是32.

如果需要将小写字母转换成大写字母,同时大写字母转换成小写字母,只需要把这个字符按位异或32即可:

1
2
b := 'A'
b ~= 32

总结

  • 大写转小写、小写转大写:字符^=32;
  • 大写转小写、小写转小写:字符|=32;
  • 小写转大写、大写转小写:字符&=-33;

完。