微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

形式 (start + 2 * i) 的所有元素的异或,其中 i 的范围从 0 到 n - 1

如何解决形式 (start + 2 * i) 的所有元素的异或,其中 i 的范围从 0 到 n - 1

背景:

这个问题实际上是在 leetcode 上归类为一个简单的问题,其解决方案的时间复杂度为 O(N)。

但是我很难通过位操作和一些观察来理解时间复杂度为 O(1) 的其他用户解决方案。

问题陈述:

给定一个整数 n一个整数 start

定义一个数组 nums,其中 nums[i] = start + 2*i(0 索引)和 n == nums.length

返回 nums 的所有元素的按位异或。

用户的 O(1) 解决方案:

class Solution {
public:
    int xorOperation(int n,int start) {
        int first = start & 1;
        start = start >> 1;
        if(start % 2 == 0){
            switch(n % 4){
                case 0: return 0;
                case 1: return ((start + n - 1) << 1) + first;
                case 2: return 2;
                case 3: return ((1 ^ (start + n - 1)) << 1) + first;
            } 
        } else {
            switch(n % 4){
                case 0: return (start ^ 1 ^ (start + n - 1)) << 1;
                case 1: return (start << 1) + first;
                case 2: return (start ^ (start + n - 1)) << 1;
                case 3: return ((start ^ 1) << 1) + first;
            } 
        }
        return 0; //unreachable
    }
};

他说当 x 是偶数时他使用了 x ^ (x + 1) = 1 的观察,但我不明白这个信息有什么用处。

一些我可能不知道的关于概念的信息会非常有用。

解决方法

不知道为什么您发布的代码如此复杂,但我想我得到了一个更易于解释(并且更易于启动)的解决方案


首先,让我们做一些观察

  1. 你总是添加一个 2 * 数字,所以 start 的最低位只是与自身进行了 n 次异或运算,这与它与n&1 (如果 n 是奇数,则保持原样,如果是偶数,则始终为 0 )。所以,让我们单独计算它,将它分流到输出端,然后处理剩下的

    int firstBit = start & n & 1;
    int startHi = start >> 1;
    // the formula now being just num[i]=startHi+i
    // ... here be computation ...
    //
    return firstBit | ( resultHi << 1 );
    
  2. xor 是关联的和它自己的逆,所以

    A^B^C^D^E^F^G^H = (A^B^C^D)^(E^F^G^H)

    (E^F^G^H) = (A^B^C^D)^(A^B^C^D^E^F^G^H)

    所以我们可以根据 xor(0...m)xor(0.. .n) 或者,就 startn 而言,我们可以

    (start+0^start+1^...start+n-1) = (0^1^2^....start-1) ^ (0^1^2^....start+n-1)

    因此让我们定义一个更简单的 1 参数函数 xor0(k),结果将是

        int firstBit = start & n & 1;
        int startHi = start >> 1;
        int resultHi = xor0(startHi)^xor0(startHi+n);
        return firstBit | ( resultHi << 1 );
    
  3. 如果我们对数字 0...k-1 进行异或运算,看看这些位是什么样子

    • 第一位像 0101 0101 0101 0101 0101,

      所以异或值就像 0110 0110 0110 0110 我们可以立即看到模式并计算

      int firstBit = (k&2)>>1;

    • 对于所有其他位,以第 2 位为例,

      它去0000 1111 0000 1111

      所以异或值是 0000 1010 0000 1010

      或位 3 0000 0000 1111 1111 0000 0000 1111 1111

      异或值是 0000 0000 1010 1010 0000 0000 1010 1010,

    我们也可以立即看到模式:如果位为 0,则保持为 0,如果位为 1,则输出在奇数 k 的 1 和偶数 k 的 0 之间交替,所以我们可以 int higherBits= (k-1) & ( (k&1)==0 ? 0 : -2 );

因此我们有了最终版本(在 Java 中,通过自我检查将其与参考 O(N) 实现进行比较)

package xortest;

public class XorTest {

    public static void main (String[] args) {
        for (int s = 0; s < 16; s++) {
            for (int n = 0; n < 16; n++) {
                int r = xorReference(s,n);
                int x = xorOperation(s,n);
                System.out.println(String.format("s=%02d n=%02d ref=%08x val=%08x%s",s,n,r,x,x == r ? "" : " ERROR"));
            }
        }
    }

    static int xor0(int k) {
        int firstBit = (k & 2) >> 1;
        int higherBits = (k - 1) & ((k & 1) == 0 ? 0 : -2);
        return higherBits | firstBit;
    }

    static int xorOperation(int start,int n) {
        int firstBit = start & n & 1;
        int startHi = start >> 1;
        int resultHi = xor0(startHi) ^ xor0(startHi + n);
        return firstBit | (resultHi << 1);
    }

    static int xorReference(int start,int n) {
        int xor = 0;
        for (int i = 0; i < n; i++) {
            xor ^= start + 2 * i;
        }
        return xor;
    }
    
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。