C++で2進表現における隣接する2つの1の間の最大0の個数を求める方法
問題概要
整数 n が与えられたとき、その2進表現において隣り合う2つの1の間に存在する0の最大個数を求めるのが課題です。ただし、2進表現に1が2つ未満しか含まれていない場合は -1 を返します。
具体例
入力が 35 の場合、2進表現は次のようになります。
00100011
この2進表現では、隣接する2つの1の間に3つの0が存在します。したがって、答えは 3 となります。
アルゴリズム
この問題はビットシフト演算子を使うことで効率的に解けます。n の2進表現の中から隣接する2つの1の位置を見つけ、その位置の差を最大化することを考えます。
- 数値が 0 または 2 のべき乗である場合(1が1つしかない場合)は -1 を返します。
- 変数
prevを、最下位側で最初に見つかった1の位置で初期化します。これは「直前に見つけた1の位置」を記憶しておくための変数です。 - もう1つの変数
curを用意し、prevの直後に現れる隣接する1の位置を格納します。 cur - prev - 1を計算すると、それが隣接する2つの1の間の0の個数になります。この値をこれまでの最大値と比較し、より大きければ更新します。その後prev = curとして次の反復に備えます。- 補助変数
setBitを使用して n の全ビットを順に走査し、現在調べているビットが 0 か 1 かを判定します。
実装例
それでは、実際のコードを見てみましょう。
#include <bits/stdc++.h>
using namespace std;
int getMaxZeros(int n) {
// 0 または 2 のべき乗の場合は -1 を返す
if (n == 0 || ((n & (n - 1)) == 0)) {
return -1;
}
int setBit = 1;
int prev = 0;
int i;
// 最下位側の最初の1の位置を探す
for (i = 1; i < sizeof(int) * 8; ++i) {
++prev;
if ((n & setBit) == setBit) {
setBit = setBit << 1;
break;
}
setBit = setBit << 1;
}
int maxZeros = INT_MIN;
int cur = prev;
// 隣接する1同士の間の0の個数を調べて最大値を更新
for (int j = i + 1; j <= sizeof(int) * 8; ++j) {
++cur;
if ((n & setBit) == setBit) {
if (maxZeros < (cur - prev - 1)) {
maxZeros = cur - prev - 1;
prev = cur;
}
}
setBit = setBit << 1;
}
return maxZeros;
}
int main() {
int n = 35;
cout << "Maximum zeros = " << getMaxZeros(n) << endl;
return 0;
}
出力結果
Maximum zeros = 3
まとめ
このアルゴリズムでは、n & setBit によるビット判定と setBit << 1 による左シフトを組み合わせることで、数値を1桁ずつ走査しながら隣接する1の位置を追跡しています。計算量は O(log n)、つまりビット長に比例した効率で処理でき、追加のメモリもほとんど不要なシンプルな手法です。
-
C++で二分木の2つのノード間の距離を求める方法
問題の概要いくつかのノードを持つ二分木が与えられているとします。このとき、2つのノード u と v の間の「距離」、つまり一方のノードからもう一方のノードへ移動する際に通る辺(エッジ)の本数を求めることを考えます。例として、次のような二分木を扱います。 1 / \ 2 3 / \ / \ 4 5 6 7 \ 8この木において、ノード (4, 6) 間の距離は 4(経路:4 → 2 → 1 → 3 → 6)、ノード (5, 8) 間の
-
【C++】二分木内の任意の2つのノード間のパスを出力する方法
はじめに 本記事では、C++プログラミングにおいて二分木(バイナリツリー)内の任意の2つのノード間のパス(経路)を出力する方法を解説します。 前提として、すべてのノードが互いに異なる値を持つ二分木が与えられ、その中から指定した2つのノードをつなぐ経路を出力することを目標とします。 例として、次のような二分木を考えます。 具体例: ノード140からノード211までの経路を出力したい場合、期待される出力は以下の通りです。 Output: 140->3->10->211 解決のアプローチ 基本的なアイデアは、「ルートノードから目的の2つのノードそれぞれへの経路」を求め、それらを