C++で2進表現における0と1の個数のXORを求める方法
問題概要
この問題では、ひとつの整数が与えられます。求めるのは、その数を2進表現したときに含まれる「0」の個数と「1」の個数をそれぞれカウントし、2つの値のXOR(排他的論理和)を計算することです。
具体例を使って、問題の内容を確認してみましょう。
入力
n = 9
出力
0
説明
binary = 1001 0の個数 = 2 1の個数 = 2 2 ^ 2 = 0
9を2進数で表すと「1001」になり、「0」が2個、「1」が2個含まれています。そこで 2 XOR 2 = 0 という結果が得られます。
解決のためのアプローチ
この問題は、次の手順で解くことができます。
- 与えられた数値を2進数として扱い、最下位ビットから順に各ビットを調べる
- ビットが「0」なら0のカウントを、「1」なら1のカウントをそれぞれ増やす
- すべてのビットを走査し終えたら、0の個数と1の個数のXORを返す
各ビットの判定には剰余演算(n % 2)を使用します。2で割った余りが0なら偶数(最下位ビットが0)、1なら奇数(最下位ビットが1)であるため、これを繰り返すことで全ビットを効率よく走査できます。
C++による実装例
上記の解法を実装したプログラムがこちらです。
サンプルコード
#include<iostream>
using namespace std;
int countXOR10(int n) {
int count0s = 0, count1s = 0;
while (n){
(n % 2 == 0) ? count0s++ : count1s++;
n /= 2;
}
return (count0s ^ count1s);
}
int main() {
int n = 21;
cout<<"XOR of count of 0s and 1s in binary of "<<n<<" is "<<countXOR10(n);
return 0;
}実行結果
XOR of count of 0s and 1s in binary of 21 is 1
コードの解説
この例では n = 21 を入力としています。21を2進数で表すと「10101」であり、「0」が2個、「1」が3個含まれます。したがって 2 XOR 3 = 1 となり、出力は「1」になります。
while ループの中では、三項演算子を使って現在の最下位ビットが0か1かを判定しています。n /= 2 によって数値を右に1ビットシフトするのと同じ効果が得られ、次のビットへ処理を進めます。ループは n が0になるまで続きます。
計算量は、2進表現の桁数(ビット数)に比例するため、時間計算量は O(log n)、補助的な変数のみで済むため空間計算量は O(1) となります。非常に効率的なアルゴリズムです。
-
C++で二分木の完全ノードを数える方法(反復法と再帰法)
本記事では、二分木に含まれる「完全ノード(フルノード)」の数を、反復法と再帰法の2つのアプローチで求める方法を解説します。完全ノードとは、左と右の子を両方持ち、どちらの子もNULLでないノードのことです。つまり、ちょうど2つの子を持つノードのみが完全ノードとして扱われます。 二分木はデータの格納に用いられる特殊なデータ構造です。「各ノードが最大2つの子までしか持てない」という制約があり、ソート済み配列並みの高速な検索性能と、連結リスト並みの高速な挿入・削除性能を兼ね備えているのが特徴です。なお、1つ以上の子を持つ非葉ノードは「親ノード」とも呼ばれます。 二分木の基本構造は以下の通りです。
-
C++で二分木の半ノード(ハーフノード)を数える方法【反復・再帰の両アプローチ】
本記事では、二分木(バイナリツリー)に含まれる「半ノード(ハーフノード)」の数を、反復処理と再帰処理の2つのアプローチで求める方法を解説します。半ノードとは?半ノードとは、子を1つだけ持ち、もう片方の子がNULL(空)になっているノードのことです。なお、子をまったく持たない葉ノードは半ノードには含まれない点に注意してください。二分木はデータの格納に使われる特殊なデータ構造です。各ノードが最大2つの子を持つという制約があり、ソート済み配列並みの高速な検索と、連結リスト並みの高速な挿入・削除の両方を実現できるというメリットがあります。二分木の基本的な構造は以下の通りです。具体例入力:出力: カウン