异或相关面试题
异或:2进制相同为0,不同为1。同时满足交换律和结合律
- 0 ^ N = N
- N ^ N = 0
同或:2进制相同为1,不同为0
题一:如何不用额外遍历交换两个数
默认情况是使用临时变量来存储一个数,最后交换。在此处我们使用异或运算,依靠异或的下列特点来进行交换。
1 | //默认情况 |
- 0 ^ N = N
- N ^ N = 0
题二:一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并且打印这种数(LeetCode136)
默认情况是使用字典进行存储,将每种数作为键进行存储,值则为出现的次数,最后循环找到奇数次的那种数.
创建一个变量赋值为 0,使用该变量异或遍历每一个数组的值,即可。
1 | static void Main(string[] args) |
题三:怎么把一个int类型的数,提取出最右侧的1来。
例如:000001110101101111001101010101 ——->000000000000000000000000000001
1 | static void Main(string[] args) |
题四:一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数(LeetCode260)
- 全员异或:通过遍历数组将所有元素异或,得到的结果
eor1是两个目标数的异或值(因为相同数异或为 0,其他数成对出现被抵消)。 - 提取差异位:计算
eor1 & (-eor1)得到2进制最右侧的 1,该位置代表两个目标数在此位上不同(一个为 0,一个为 1)。 - 分组异或:再次遍历数组,将元素分为两类:在该位为 1 的和为 0 的。由于其他数都是偶数次出现,分组后异或会抵消。而两个目标数因该位不同被分到不同组,最终
eor2会得到其中一个目标数。 - 计算另一个数:用初始异或结果
eor1异或eor2,即可得到另一个目标数。 - 时间复杂度O(n),空间复杂度为 O(1)
1 | static void Main(string[] args) |
题五:一个数组中有一种数出现K次,其他数都出现了M次,M>1,K<M,找到出现了K次的数,要求,额外空间复杂度O(1),时间复杂度O(N)
初始化计数器数组:创建长度为 32 的数组
t,用于统计每个二进制位(第 0 位到第 31 位)上 1 的出现总次数。统计每位的出现次数:遍历数组中每个元素,对其每个二进制位进行判断:
- 若元素的第
i位为 1,则将t[i]加 1。
- 若元素的第
构建结果:遍历计数器数组
t,对于每个二进制位i:- 若
t[i]不是m的倍数(即t[i] % m != 0),说明该位在目标元素中为 1。
- 若
时间复杂度O(n),空间复杂度 O(1)
由于其他元素均出现
m次,它们在每个二进制位上的贡献总和必然是m的倍数。而目标元素出现k次,其对应位的总次数为m的倍数 + k,因此通过取模运算可直接定位目标元素的二进制位。
1 | public static int onlyKTimes(int[] arr,int k,int m) |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 岁迹!
