2 つの整数 a と b が与えられた場合、b が a の回転バージョンであることをどのように確認できますか?
たとえば、a = 0x01020304
(バイナリで0000 0001 0000 0010 0000 0011 0000 0100
)持っている場合、次の b 値は正しいです:
- ...
0x4080C1
(右に 2 回転)0x810182
(右に 1 回転)0x2040608
(左に 1 回転)0x4080C10
(左に 2 回転)- ...
2 つの整数 a と b が与えられた場合、b が a の回転バージョンであることをどのように確認できますか?
たとえば、a = 0x01020304
(バイナリで0000 0001 0000 0010 0000 0011 0000 0100
)持っている場合、次の b 値は正しいです:
0x4080C1
(右に 2 回転)0x810182
(右に 1 回転)0x2040608
(左に 1 回転)0x4080C10
(左に 2 回転)n ビット数の場合、KMP アルゴリズムを使用して、複雑さ O(n) の a の 2 つのコピー内で b を検索できます。
ループで実行する必要があると思います(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;
一般的な場合 (任意の長さの整数を想定)、各回転を構成する単純な解は O(n^2) です。
しかし、あなたが効果的に行っているのは相関関係です。また、FFT を使用して周波数領域を経由することで、O(n log n) 時間で相関を行うことができます。
ただし、これは長さ 32 の整数ではあまり役に立ちません。
ここで回答を導き出すことにより、次のメソッド (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 の回転バージョンです。
a
orが定数 (またはループ定数) の場合b
、すべての回転を事前に計算して並べ替え、定数ではないものをキーとしてバイナリ検索を実行できます。これはステップ数が少ないですが、実際にはステップが遅くなるため (二分探索は通常、予測が不十分な分岐で実装されます)、より良い方法ではない可能性があります。
ループ定数ではなく、実際に定数である場合は、さらにいくつかのトリックがあります。
a
0または-1の場合、それは自明ですa
は、次のようにテストできますb != 0 && (b & (b - 1)) == 0
a
、次のようなテストを実行できますror(b, tzcnt(b)) == ror(a, tzcnt(a))
設定されたビットの連続したグループが 1 つしかない場合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
できる場合があります。b == a || (b << 1) == a
popcnt
。もちろん、最初に述べたように、a
とb
が両方とも変数である場合、これは当てはまりません。
私は使用Integer.rotateLeft
またはrotateRight
機能します
static boolean isRotation(int a, int b) {
for(int i = 0; i < 32; i++) {
if (Integer.rotateLeft(a, i) == b) {
return true;
}
}
return false;
}