奇妙的位运算

三道leetcode上的题目。

Single Number

Given an array of integers, every element appears twice except for one. Find that single one.

题意即:一个数组,里面的元素每个都出现了两次,除了一个特殊的,求这个特殊元素。接触过这类题目的coder很快能够脱口而出:直接异或就ok了!因为两个相同的数异或会抵消每个bit位,结果为0.

1 class Solution {
2 public:
3     int singleNumber(vector<int>& nums) {
4         int x=0,len=nums.size();
5         for(int i=0;i<len;i++)  x^=nums[i];
6         return x;
7     }
8 };

Single Number II

Given an array of integers, every element appears three times except for one. Find that single one.

题意:这是上题的加强版,数组中每个元素都出现三次,除了一个特殊的,找出这个特殊元素。

思路:我们也可以按位运算,计算1 bit的数量,如果每个数字都出现三次,那么每位上的1 bit数量肯定是3的倍数,相反如果不是3的倍数,那么就是那个特殊的数。但是我们可以用一个数“辅助”,因为每一位的1 bit数量统计都是类似的,所以假设正在统计某一位的1 bit数量。我们用a来表示 1 bit 的数量,当 1 bit 的数量为0时,a=0;当数量为1时,a=1;当数量为2时,a=2?非也,位运算只能表示0和1,所以这时我们引进第二个变量b,我们用b=1来代表已经有了2个 1 bit,所以当有两个 1 bit 时,a=0,b=1。数量统计结果逢3化0,所以只有0、1、2三种结果:

bits数量    a     b
   0        0     0
   1        1     0
   2        0     1

思路也就显而易见了,每次运算我们维护a和b的值,运算到最后即可得到结果:

 1 class Solution {
 2 public:
 3     int singleNumber(vector<int>& nums) {
 4         int a=0,b=0,len=nums.size();
 5         for(int i=0;i<len;i++){
 6             b=a&(b^nums[i]);//b由a和b异或item的对应bit与决定
 7             a=b|(a^nums[i]);//a由b和a异或item的对应bit或决定
 8         }
 9         return a;
10     }
11 };

Single Number III

Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.

For example:

Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].

题意:还是一个数组,每个元素出现两次,只有两个特殊的元素出现一次,把这两个特殊的元素找出来。

思路:直接异或不得行。考虑两个特殊值,他们肯定有bit不同,想办法分开他们,再分别与其他数异或,就出来了。把所有数异或(效果等同于把两特殊数异或),取结果某个bit上的1,根据此位把数组分为两个子数组,则目的达到。

 1 class Solution {
 2 public:
 3     vector<int> singleNumber(vector<int>& nums) {
 4         int x=0,len=nums.size();
 5         for(int i=0;i<len;i++)  x^=nums[i];
 6         x=x&(-x);//取x最右边为1的bit位
 7         int r1=0,r2=0;
 8         for(int i=0;i<len;i++) (nums[i]&x)?(r1^=nums[i]):(r2^=nums[i]);
 9         vector<int> t;
10         t.push_back(r1);
11         t.push_back(r2);
12         return t;
13     }
14 };

 

参考:http://www.cnblogs.com/zichi/p/4795049.html

<think>好的,用户想了解异或运算在编程中的特殊用途和技巧。首先,我得回忆一下异或运算的基本性质。异或(XOR)在二进制中,相同为0,不同为1。这个特性让它在很多场景下非常有用。 接下来,我应该整理常见的应用场景。比如,交换两个变量的值而不使用临时变量,这个我记得是一个经典技巧。然后,数据校验中的奇偶校验或者简单的错误检测也可能用到异或。还有,加密算法中异或也经常被使用,因为它可逆,比如两次异或同一个数会得到原值。 另外,用户可能对算法题中的异或应用感兴趣。比如在数组中找出唯一出现一次的数字,其他都出现两次的情况,用异或可以高效解决。还有,异或可以用来判断两个数是否符号相反,或者在不使用加法的情况下实现加法运算,虽然这可能需要更深入的位操作。 需要注意用户提到的“奇妙用法”和“技巧”,所以需要举一些直观的例子,比如交换变量、找单个数、加密解密等。同时,结合用户提供的引用资料,引用3提到了位运算在解题中的妙处,可以引用这一点来支持示例。 还要检查是否有其他技巧,比如图形学中的XOR绘图,或者内存重叠检测,但可能这些对用户来说比较复杂,先以基础且实用的例子为主。 另外,用户提供的引用4提到Lua的元表和方法,可能和运算符重载有关,但异或本身在Lua中可能需要实现,但用户的问题可能更偏向通用编程,所以可以暂时忽略这部分。 最后,确保每个例子都有代码示例,并正确使用LaTeX格式,比如变量用$符号包裹,独立公式用$$。同时,生成相关问题时要围绕异或运算的其他应用、优缺点、算法题等展开。 总结一下,回答的结构应该是先介绍异或的概念,然后分点列出应用场景,每个场景配以代码示例和解释,最后生成相关问题。需要确保引用正确的参考文献,比如引用3关于位运算的解题妙用,引用4可能涉及运算符重载但可能不直接相关,引用3更相关。</think>### 异或运算在编程中的特殊用途技巧 异或运算(XOR)在编程中因其独特的二进制特性(**相同为0,不同为1**)常被用于巧妙解决问题。以下是几个经典应用场景: --- #### 1. **变量交换(无需临时变量)** 通过异或运算可以交换两个整型变量的值,避免使用额外内存空间: ```python a = 5 b = 3 a ^= b # a = 5 ^ 3 b ^= a # b = 3 ^ (5 ^ 3) = 5 a ^= b # a = (5 ^ 3) ^ 5 = 3 print(a, b) # 输出3,5 ``` **原理**:利用异或的**自反性**,即 $(x \oplus y) \oplus y = x$[^3]。 --- #### 2. **快速查找唯一不重复数** 在数组中若**仅有一个数出现一次,其他数均出现两次**,可用异或高效找出该数: ```python def find_unique(arr): result = 0 for num in arr: result ^= num return result arr = [4, 1, 2, 1, 2] print(find_unique(arr)) # 输出4 ``` **原理**:异或满足**交换律和结合律**,成对出现的数异或结果为0,最终剩余唯一数[^3]。 --- #### 3. **简单数据加密** 异或的可逆性可用于基础的加密解密: ```python def xor_crypt(text, key): return ''.join(chr(ord(c) ^ key) for c in text) message = "Hello" key = 42 encrypted = xor_crypt(message, key) # 加密 decrypted = xor_crypt(encrypted, key) # 解密(再次异或同一key) print(decrypted) # 输出Hello ``` **注意**:实际加密需结合更复杂算法,此方法仅用于演示原理[^3]。 --- #### 4. **判断两数符号是否相反** 利用异或的最高位特性,快速判断两整数符号是否不同: ```python def opposite_sign(a, b): return (a ^ b) < 0 print(opposite_sign(5, -3)) # 输出True print(opposite_sign(5, 3)) # 输出False ``` **原理**:若符号位不同,异或结果的最高位为1,值为负数。 --- #### 5. **位操作实现加法** 异或结合运算可实现二进制加法(需处理进位): ```python def add_without_plus(a, b): while b != 0: carry = (a & b) << 1 # 进位 a = a ^ b # 无进位和 b = carry return a print(add_without_plus(7, 5)) # 输出12 ``` **原理**:异或计算无进位和,运算左移1位计算进位,循环至无进位。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值