C++で2つの数値の右端から最初に異なるビットの位置を求める方法
問題の概要
この問題では、2つの整数 N と M が与えられます。目的は、それぞれの数値を2進数で表したときに、右側(最下位ビット側)から見て最初に異なるビットが現れる位置(インデックス)を求めることです。
具体例
- 入力: N = 12、M = 10
- 出力: 2
- 説明: (12)10 = (1100)2、(10)10 = (1010)2。右から2番目のビットだけが異なっています。
解き方の考え方:XORを活用する
2つの数値の「異なるビット」をすべて見つけるには、XOR(排他的論理和) を使うのが最も効果的です。XORは対応するビットが異なる場合にのみ1を返すため、N ^ M の結果には「異なるすべてのビット」が1として現れます。
あとは、その結果(N ^ M)の中で最も右側にあるセットされたビット(1になっているビット)の位置を特定すればよいことになります。
N = 12 , M = 10 N^M = 0110
この例では、右端のセットされたビットはインデックス2の位置に存在します。
右端のセットビットを求めるテクニック
任意の整数 x に対して x & -x を計算すると、x の中で最も下位にあるセットビットだけが残ります。これは2の補数表現の性質を利用した有名なビットトリックです。さらにこれに log2 を適用すれば、そのビットの指数(0始まりの位置)が得られるため、+1 することで1始まりのインデックスに変換できます。
実装例(C++)
上記のアプローチを実装したプログラムがこちらです。
#include <iostream>
#include <math.h>
using namespace std;
int rightSetBit(int N) {
int bitIndex = log2(N & -N) + 1;
return bitIndex;
}
void rightDiffBit(int m, int n) {
int diffBit = rightSetBit(m^n);
cout << diffBit;
}
int main() {
int N = 12, M = 10;
cout << "Postion of first right different bit of the number " << N << " & " << M << " is ";
rightDiffBit(N, M);
return 0;
}
出力
Postion of first right different bit of the number 12 & 10 is 2
まとめ
この解法のポイントは次の2つです。
- N ^ M によって「異なるビットだけが立った数」を作り出す
- N & -N と log2 を組み合わせて、最下位のセットビットの位置を効率的に求める
各ビットをループで順番に比較する方法と比べ、ビット演算を組み合わせることでコードが簡潔になり、より高速に答えを得ることができます。
-
C++で解説:T秒後のカエルの位置を求める確率計算アルゴリズム
n個の頂点からなる無向木(ツリー)があるとします。頂点には1からnまでの番号が付けられており、カエルは頂点1からジャンプを開始します。カエルは、現在いる頂点に隣接している「未訪問」の頂点へ、1秒でジャンプすることができますが、一度訪れた頂点へ戻ることはできません。ジャンプ先の候補が複数ある場合は、いずれも等しい確率でランダムに1つを選んで移動します。逆に、行ける未訪問の頂点がなくなったカエルは、その場で永遠に跳ね続けることになります。 木は辺の配列として与えられます。ここで求めたいのは、「t秒後にカエルが頂点targetの上にいる確率」です。 問題の例 たとえば、入力が n = 7、t = 2
-
C++で円上に立つ人の真向かいの位置を求めるアルゴリズム
問題概要 この問題では、2つの整数 N と M が与えられます。円の周りにはN人が等間隔で立っており、Mはそのうちのある一人の人の位置を表しています。私たちのタスクは、位置Mにいる人と正反対(直径を挟んで向かい合う)にいる人の位置を出力することです。 入出力例 入力: N = 6、M = 3 出力: 6 説明: 円の周りに6人が立っているとき、位置3にいる人と向かい合うのは位置6の人です。 解き方の考え方 円の中心を挟んで正反対の位置は、必ずちょうど半分(N/2)だけ離れた場所にあります。この性質を使うと、対象の人が円の前半にいるか後半にいるかによって、次の2つの場合に分けて考えることがで