C++でn個のセットビットとm個のアンセットビットを持つ最大の数を求める方法
この記事では、2つの整数値 n と m が与えられたとき、2進数表現において n 個のセットビット(1)と m 個のアンセットビット(0)を持つ最大の数を求める方法について解説します。
問題の理解
まず、具体的な例で問題を確認してみましょう。
入力 : n = 3, m = 1
出力 : 14
説明:
最大の数になるのは、上位に3つのセットビットが並び、その下位に1つのアンセットビットが続くパターンです。
(1110)2 = 14
解法アプローチ
この問題へのシンプルなアプローチは、まず (n + m) 個すべてのビットがセットされた数を作成し、そこから下位(LSB側)の m ビットをオフにするというものです。
(n + m) 個のセットビットを持つ数は、次の式で簡単に生成できます。
$$(1\ll(n+m))-1$$
さらに、下位 m ビットだけがセットされたマスク値 $$(1\ll m)-1$$ を用意し、元の数とXOR演算を行うことで、下位 m ビットを反転(0に)できます。これにより、上位 n ビットが1、下位 m ビットが0となる最大の数が得られます。
実装例
上記のソリューションの動作を示すC++プログラムは以下の通りです。
#include <iostream>
using namespace std;
int findlargestNumber(int n, int m){
int maxNum = (1 << (n + m)) - 1;
if (m == 0)
return maxNum;
int number = (1 << m) - 1;
return (maxNum ^ number);
}
int main(){
int n = 5,
m = 2;
cout<<"The largest number with "<<n<<" set bits and "<<m<<" unset bits is "<<findlargestNumber(n, m);
return 0;
}
出力
The largest number with 5 set bits and 2 unset bits is 124
コードの解説
(1 << (n + m)) - 1: 下位 (n + m) ビットがすべて1になった数を生成します。(1 << m) - 1: 下位 m ビットだけが1になったマスク値を生成します。- XOR演算(
^)によって、maxNum の下位 m ビットが0に切り替わり、目的の数が完成します。
m が 0 の場合は、すべてのビットがセットされた状態がそのまま答えになるため、maxNum をそのまま返しています。
計算量
- 時間計算量: O(1) ― ビット演算のみで構成されるため定数時間で処理できます。
- 空間計算量: O(1) ― 追加のメモリは不要です。
-
C++で集合の反射関係の数を求める方法
この記事では、C++を使って集合上に定義できる反射関係(reflexive relation)の総数を求める方法について解説します。問題設定としては、整数 n が与えられたとき、n 個の自然数からなる集合上に存在する反射関係の個数を求めるというものです。 反射関係とは 集合 A 上の関係 R が反射的であるとは、「A に属するすべての要素 a に対して、順序対 (a, a) が必ず R に含まれる」という条件を満たすことを意味します。数式で表すと次のようになります。 (a, a) ∈ R (∀ a ∈ A) 具体的な入出力の例を見てみましょう。 入力 : x = 1 出力 : 1 説明 : 集
-
C++である数値のセットビットと未セットビットの数が同じかどうかを判定する方法
この記事では、ある整数の2進数表現において、セットビット(1となっているビット)と未セットビット(0となっているビット)の数が同じかどうかを判定する方法を解説します。例として、数値12を考えてみましょう。12の2進数表現は「1100」です。この中には1が2つ、0が2つ含まれており、セットビットと未セットビットの数が一致しています。アルゴリズムの考え方アプローチは非常にシンプルです。以下の手順で判定を行います。数値の最下位ビットから順に、1ビットずつ値を調べます。調べたビットが1であればセットビットのカウンター(set_count)を、0であれば未セットビットのカウンター(unset_count