给定两个整数a和b,我们如何检查b是旋转版本的?
例如,如果我有a = 0x01020304
(二进制0000 0001 0000 0010 0000 0011 0000 0100
),则以下b值是正确的:
0x4080C1
(右转2)0x810182
(右转1)0x2040608
(左转1)0x4080C10
(左转2)答案 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.rotateLeft
或rotateRight
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)
如果a
或b
是一个常量(或循环常量),您可以预先计算所有旋转并对它们进行排序,然后使用不是常量的旋转进行二进制搜索键。这个步骤较少,但实际步骤较慢(二进制搜索通常用错误预测的分支实现),所以它可能不会更好。
如果它确实是一个常量,而不是循环常量,那么还有一些技巧:
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
测试外,您还可以比较常数的最小和最大旋转,以进行快速预测试。当然,正如我在开头所说,当popcnt
和a
都是变量时,这一点都不适用。