C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++で2つの数値の右端から最初に異なるビットの位置を求める方法


問題の概要

この問題では、2つの整数 NM が与えられます。目的は、それぞれの数値を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 & -Nlog2 を組み合わせて、最下位のセットビットの位置を効率的に求める

各ビットをループで順番に比較する方法と比べ、ビット演算を組み合わせることでコードが簡潔になり、より高速に答えを得ることができます。

  1. C++で解説:T秒後のカエルの位置を求める確率計算アルゴリズム

    n個の頂点からなる無向木(ツリー)があるとします。頂点には1からnまでの番号が付けられており、カエルは頂点1からジャンプを開始します。カエルは、現在いる頂点に隣接している「未訪問」の頂点へ、1秒でジャンプすることができますが、一度訪れた頂点へ戻ることはできません。ジャンプ先の候補が複数ある場合は、いずれも等しい確率でランダムに1つを選んで移動します。逆に、行ける未訪問の頂点がなくなったカエルは、その場で永遠に跳ね続けることになります。 木は辺の配列として与えられます。ここで求めたいのは、「t秒後にカエルが頂点targetの上にいる確率」です。 問題の例 たとえば、入力が n = 7、t = 2

  2. C++で円上に立つ人の真向かいの位置を求めるアルゴリズム

    問題概要 この問題では、2つの整数 N と M が与えられます。円の周りにはN人が等間隔で立っており、Mはそのうちのある一人の人の位置を表しています。私たちのタスクは、位置Mにいる人と正反対(直径を挟んで向かい合う)にいる人の位置を出力することです。 入出力例 入力: N = 6、M = 3 出力: 6 説明: 円の周りに6人が立っているとき、位置3にいる人と向かい合うのは位置6の人です。 解き方の考え方 円の中心を挟んで正反対の位置は、必ずちょうど半分(N/2)だけ離れた場所にあります。この性質を使うと、対象の人が円の前半にいるか後半にいるかによって、次の2つの場合に分けて考えることがで