C++ 异或运算直觉

C++ 异或运算直觉,c++,bit-manipulation,C++,Bit Manipulation,我最近遇到了一个关于Leetcode的问题,并找到了一个需要澄清的解决方案: 给定一个整数数组,除了一个之外,每个元素都会出现两次。找到那个 注: 您的算法应该具有线性运行时复杂性。你能在不使用额外内存的情况下实现它吗 类解决方案{ 公众: 整数单数(向量和nums){ int结果=0; 用于(自动和控制:nums){ 结果^=c; } 返回结果; } }; 首先,我应该注意什么类型的关键字,以便弄清楚我应该对这个问题使用XOR运算 还有,为什么向量中的所有项彼此异或会得到一个不重复的项 感

我最近遇到了一个关于Leetcode的问题,并找到了一个需要澄清的解决方案:

给定一个整数数组,除了一个之外,每个元素都会出现两次。找到那个

注: 您的算法应该具有线性运行时复杂性。你能在不使用额外内存的情况下实现它吗

类解决方案{
公众:
整数单数(向量和nums){
int结果=0;
用于(自动和控制:nums){
结果^=c;
}
返回结果;
}
};
首先,我应该注意什么类型的关键字,以便弄清楚我应该对这个问题使用XOR运算

还有,为什么向量中的所有项彼此异或会得到一个不重复的项


感谢大家的回复,下面是其他感兴趣的人关于按位属性的更多信息:

异或运算符是可交换的:

和关联:

因此,任何
xor
操作序列的结果都完全独立于操作数的顺序(即数组中元素的顺序)


在这个问题中,我们有一个表达式,其中每个元素Ai出现两次,除了一些奇异元素B。得到的异或运算等价于:

     (A1 ⊕ A1) ⊕ (A2 ⊕ A2) ⊕    ...   ⊕ B
 = 
         0      ⊕      0     ⊕    ...   ⊕ B
 = 
         B

我应该注意哪些类型的关键字,以便弄清楚我应该对这个问题使用XOR运算

使用位操作可以快速解决一些问题。在熟悉了布尔运算符及其属性,并看到了足够多的像这样的应用程序之后,您自然会“感觉”到它们对解决给定问题有用

  • A^0==A

  • A^A==0

  • A^B==B^A

  • (A^B)^C==A^(B^C)

  • (3) 和(4)加在一起意味着数字的异或顺序无关紧要

    这意味着,例如,
    A^B^X^C^B^A^C
    等于
    A^A^B^B^C^C^X

    因为(2)等于
    0^0^0^X

    因为(1)等于
    X



    我不认为有任何特定的关键字可以帮助您识别此类问题。您应该知道XOR的上述属性。

    XOR总是以二进制数字(或一些等价的概念,如true或false语句)来定义的。除了二进制表示的相应位的异或外,整数没有特殊的异或

    设A和B为两个布尔变量,设XOR为接受两个布尔变量的布尔函数。
    A.⊕如果(A=0和B=1)或(A=1和B=0)(即两者不同),则B=1,
    A.⊕如果(A=0和B=0)或(A=1和B=1),则B=0。(即它们是相同的)

    因此,考虑到你的问题,因为在给定的n个向量元素中,除了一个元素外,每个元素都出现两次,这个想法是 重复数的二进制表示形式是相同的,因此,XOR结果将相互抵消为1⊕1=0和0⊕0=0

    对于A=5,其二进制表示为101,因此A⊕A=(101)⊕(101)=000,其十进制表示为0

    请记住,数字的顺序并不重要,因为((A⊕(B)⊕C) =(A)⊕(B)⊕C) )。 最终,对每个数字进行XOR运算后,最后得到的是一次出现的数字

    要回答您关于何时需要使用异或运算来解决问题的问题,请练习一些位操作问题,最终您将能够理解。
    提示:要求查找除rest之外具有唯一属性的元素的问题需要位操作。

    示例:给定一个数组,其中每个元素出现三次,只有一个元素只出现一次。查找一次出现的元素。

    将异或与其他逻辑运算符区分开来的关键直观方面是它是无损耗的,也就是说,与(在这方面更类似于),它是确定可逆的:在给定剩余的计算历史的情况下,您可以精确地恢复其中一个输入值

    下图说明了以及都至少有一种情况,其中一个输入的状态在给定另一个输入的特定值时是不可恢复的。我将这些表示为“丢失”输入

    对于异或门,考虑到剩余的计算历史,不存在无法恢复输入或输出值的情况。事实上,有一种对称性,知道三元组
    (in0,in1,out)
    的任意两个值可以恢复第三个值。换句话说,无论输入或输出如何,这三个值中的每一个都是其他两个值的异或

    这张图片表明,另一种看待异或操作的方式是将其看作一个可控的非门。通过切换其中一个输入(上例中的上一个),可以控制另一个(下一个)输入是否为负

    另一个等价的观点是,XOR实现了不等于(≠) 函数相对于其两个输入。因此,也等于下的函数(=)

    根据其对称性和信息保持特性,XOR应该考虑需要可逆性或完美数据恢复的问题。最明显的例子是,XOR使用恒定的“键”对数据集进行加密会使数据变得模糊,从而知道键(可能是kep)
    1.      X ⊕ Y = Y ⊕ X                    for any integers X and Y
    
    2.      X ⊕ (Y ⊕ Z) = (X ⊕ Y) ⊕ Z      for any integers X, Y and Z
    
    3.     X ⊕ X = 0                         for any integer X
    
    4.     X ⊕ 0 = 0 ⊕ X = X                for any integer X
    
         (A1 ⊕ A1) ⊕ (A2 ⊕ A2) ⊕    ...   ⊕ B
     = 
             0      ⊕      0     ⊕    ...   ⊕ B
     = 
             B
    
    uint GetHashCode(ulong ul)
    {
        return (uint)ul ^ (uint)(ul >> 32); 
    }
    
    unsigned int v;       // the value to modify
    unsigned int m;       // mask: the bits to set or clear
    int f;                // condition: 0 to 'set', or 1 to 'clear'
    
    v ^= (-f ^ v) & m;    // if (f) v |= m; else v &= ~m;
    
    class Solution:
        def singleNumber(self, nums):
            return (sum(set(nums)) << 1) - sum(nums)
    
    // The following block might slightly improve the execution time;
    // Can be removed;
    static const auto __optimize__ = []() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cout.tie(nullptr);
        return 0;
    }();
    
    // Most of headers are already included;
    // Can be removed;
    #include <cstdint>
    
    using ValueType = std::uint_fast16_t;
    
    static const struct Solution {
        static const int singleNumber(
            const std::vector<int> nums
        ) {
            ValueType single_number = 0;
    
            for (ValueType index = 0; index < std::size(nums); index++) {
                single_number ^= nums[index];
            }
    
            return single_number;
        }
    };
    
    
    public final class Solution {
        public static final int singleNumber(
            final int[] nums
        ) {
            int singleNumber = 0;
    
            for (int index = 0; index != nums.length; index++) {
                singleNumber ^= nums[index];
            }
    
            return singleNumber;
        }
    }