算法--位运算

位运算在算法中有时候能够起奇效

C语言位运算符列表

运算符名称描述示例
&按位与两操作数对应位均为1时结果为1a & b
``按位或两操作数对应位至少一个为1时结果为1
^按位异或两操作数对应位不同时结果为1a ^ b
~按位取反反转操作数的所有位(单目运算)~a
<<左移将二进制位左移指定位数a << n
>>右移将二进制位右移指定位数a >> n

乘 2

a * 2 == a << 1,正负通用,即左移一位,二进制全体位数左移一位,整数翻倍,与普通运算一样有可能超出整型边界。由于负数采用补码表示,左移高位符号位丢失,但是符号位后方同样是 1,因此正负通用。

除 2

a / 2 == a >> 1,即带符号右移一位,二进制全体位数右移一位,最高位补原有符号位,由于是整数除法,必定会出现无法整除的情况,此时正负数的结果是不同的:

正数:与普通除法一致,若无法整除,向下取整,如 11 / 2 == 11 >> 1 == 5。

负数:与普通除法不一致,若无法整除,向下取整,而普通除法是向上取整的

判断奇偶

a & 1,“and 1” 操作保留最后一位,由于奇数最后一位为 1,偶数最后一位为 0,因此:

a & 1 == 1,a 为奇数。
a & 1 != 1,a 为偶数

交换两个数

通过二进制交换两个数。

a ^= b;
b ^= a;
a ^= b;

一个数与两个相同的数进行异或运算,结果必定等于自己;因为异或的结果是保留对方与自身位值不同的地方,也就是两个二进制数有差异的位,再拿这些有差异的位去对方身上异或运算,那就是自己了

a ^= b 时,a 的值为 a ^ b;
b ^= a 等于 b = b ^ (a ^ b) 等于 a;
a ^= b 等于 a = (a ^ b) ^ a 等于 b;

注意!数组存在特殊情况,nums[i] 与 nums[i] 交换时 nums[i] 将变成 0。因为异或交换两个数的前提是两个数分开存储,如果对于同一数组元素进行这么操作,由于只有一个存储单元,自己与自己异或会清空所有的 1 位,将变为 0,原理等同于 a 与 a 使用异或交换。

举例:

异或找出重复的元素:1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次
思路
1^2^...^n^...^n^...^1000,无论这两个n出现在什么位置,都可以转换成为1^2^...^1000^(n^n)的形式。
其次,对于任何数x,都有x^x=0,x^0=x。
1^2^...^n^...^n^...^1000 = 1^2^...^1000^(n^n)= 1^2^...^1000^0 = 1^2^...^1000(即序列中除了n的所有数的异或)。
令,1^2^...^1000(序列中不包含n)的结果为T
则1^2^...^1000(序列中包含n)的结果就是T^n。
T^(T^n)=n。
所以,将1^2^3^...^1000的结果和数组中所有的数异或,得到的结果就是重复数。

找不同

给定两个字符串 s 和 t ,它们只包含小写字母。

字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。

请找出在 t 中被添加的字母。

示例 1:

输入:s = "abcd", t = "abcde"
输出:"e"
解释:'e' 是那个被添加的字母。

示例 2:

输入:s = "", t = "y"
输出:"y"

首先分析题目找出只有一个数量的数据,这时候可以想到使用异或,但是异或需要通过两个相同数据来实现 a 异或 a = 0

所以要想把两个字符串中内容全部异或,最终结果返回的就是单独存在的字母

给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

    268. 丢失的数字

    示例 1:

    输入:nums = [3,0,1]

    输出:2

    解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。

    示例 2:

    输入:nums = [0,1]

    输出:2

    解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。

    示例 3:

    输入:nums = [9,6,4,2,3,5,7,0,1]

    输出:8

    解释:n = 9,因为有 9 个数字,所以所有的数字都在范围 [0,9] 内。8 是丢失的数字,因为它没有出现在 nums 中。

    int missingNumber(int* nums, int numsSize) {
         int n = numsSize;
         int i = 0;
         for(int j = 0; j <numsSize ;j++){
            i = i ^ nums[j] ^ j;
         }
         i = i ^ n;
         return i;
    }

    参考Leetcode链接:

    https://leetcode.cn/circle/discuss/CWtfko/

    https://leetcode.cn/circle/discuss/mDhWhf/

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值