检查整数是另一个整数的位旋转

时间:2013-06-07 08:38:20

标签: java c++ rotation bit-manipulation

给定两个整数a和b,我们如何检查b是旋转版本的?

例如,如果我有a = 0x01020304(二进制0000 0001 0000 0010 0000 0011 0000 0100),则以下b值是正确的:

  • ...
  • 0x4080C1(右转2)
  • 0x810182(右转1)
  • 0x2040608(左转1)
  • 0x4080C10(左转2)
  • ...

7 个答案:

答案 0 :(得分:6)

对于n位数,您可以使用KMP algorithm在复杂度为O(n)的两个副本中搜索b。

答案 1 :(得分:5)

在C ++中,没有字符串转换并假设32位int:

void test(unsigned a, unsigned b)
{
  unsigned long long aa = a | ((unsigned long long)a<<32);
  while(aa>=b)
  {
    if (unsigned(aa) == b) return true;
    aa>>=1;
  }
return false;
}

答案 2 :(得分:4)

我认为你必须在循环中完成它(c ++):

// rotate function
inline int rot(int x, int rot) {
   return (x >> rot) | (x << sizeof(int)*8 - rot));
}

int a = 0x01020304;
int b = 0x4080C1;
bool result = false;

for( int i=0; i < sizeof(int)*8 && !result; i++) if(a == rot(b,i)) result = true;

答案 3 :(得分:3)

在一般情况下(假设任意长度整数),每个旋转组成的朴素解是O(n ^ 2)。

但你实际做的是相关性。你可以在going via the frequency domain using an FFT的O(n log n)时间内进行相关。

但这对长度为32的整数没有多大帮助。

答案 4 :(得分:1)

通过派生答案here,下面的方法(用C#编写,但在Java中应该类似)应该进行检查:

public static int checkBitRotation(int a, int b) {
    string strA = Convert.ToString(a, 2).PadLeft(32, '0');
    string strB = Convert.ToString(b, 2).PadLeft(32, '0');
    return (strA + strA).IndexOf(strB);
}

如果返回值为-1,则b不是a的旋转版本。否则,b是a。的旋转版本。

答案 5 :(得分:0)

我会使用Integer.rotateLeftrotateRight func

static boolean isRotation(int a, int b) {
    for(int i = 0; i < 32; i++) {
        if (Integer.rotateLeft(a, i) == b) {
            return true;
        }
    }
    return false;
}

答案 6 :(得分:0)

如果ab是一个常量(或循环常量),您可以预先计算所有旋转并对它们进行排序,然后使用不是常量的旋转进行二进制搜索键。这个步骤较少,但实际步骤较慢(二进制搜索通常用错误预测的分支实现),所以它可能不会更好。

如果它确实是一个常量,而不是循环常量,那么还有一些技巧:

  • 如果a为0或-1,则很简单
  • 如果a只设置了1位,则可以像b != 0 && (b & (b - 1)) == 0
  • 那样进行测试
  • 如果a设置了2位,则可以执行ror(b, tzcnt(b)) == ror(a, tzcnt(a))
  • 之类的测试
  • 如果a只有一个连续的设置位组,则可以使用

    int x = ror(b, tzcnt(b));
    int y = ror(x, tzcnt(~x));
    const int a1 = ror(a, tzcnt(a));     // probably won't compile
    const int a2 = ror(a1, tzcnt(~a1));  // but you get the idea
    return y == a2;
    
  • 如果a的多次旋转相同,您可以使用它来跳过某些旋转而不是全部测试,例如a == 0xAAAAAAAA,测试可以是{{1} }
  • b == a || (b << 1) == a测试外,您还可以比较常数的最小和最大旋转,以进行快速预测试。

当然,正如我在开头所说,当popcnta都是变量时,这一点都不适用。