C++で1つのセットビットを変更して得られる、nより小さい最大の整数
問題の概要
この問題では、整数 n が与えられます。求められているのは、n の2進数表現における「セットビット(1になっているビット)」を1つだけ変更することで作れる数のうち、n より小さい最大の整数を出力することです。
具体例を見てみましょう。
入力: n = 3 出力: 2 解説: (3)10 = (011)2 セットビットを1つ反転すると、001 と 010 が得られます。このうち大きいのは 010、すなわち 2 です。
解き方のアプローチ
この問題を解く鍵は、「最も右側にあるセットビット」に注目することです。n より小さくなるようにビットを1つだけ変更するなら、最下位のセットビットを0に反転するのが最適です。これにより、1ビットの変更で実現できる n 未満の最大の整数が得られます。
直感的に考えると、より上位のビットを0にすると数値は大きく減少してしまいますが、最下位のセットビットを0にすれば減少量は最小限に抑えられます。
C++による実装例
以下は、この解法を実装したC++プログラムです。
#include<iostream>
#include<math.h>
using namespace std;
int returnRightSetBit(int n) {
return log2(n & -n) + 1;
}
void previousSmallerInteger(int n) {
int rightBit = returnRightSetBit(n);
cout<<(n&~(1<<(rightBit - 1)));
}
int main() {
int n = 3452;
cout<<"The number is "<<n<<"\nThe greatest integer smaller than the number is : ";
previousSmallerInteger(n);
return 0;
}実行結果
The number is 3452 The greatest integer smaller than the number is : 3448
コードの解説
n & -n: 2の補数表現を利用したテクニックで、n の最下位のセットビットだけを取り出します。log2(...) + 1: 取り出したビットの位置(右から何番目か)を求めます。n & ~(1 << (rightBit - 1)): 該当する位置のビットだけを0にクリアし、目的の整数を生成します。
この例では n = 3452 の場合、出力は 3448 となり、確かに1ビットの変更で得られる n 未満の最大整数になっています。
-
C++でセットビット数に基づいて配列をソートする方法
今回は、配列を「セットビット」の数に基づいてソートするという興味深い問題を取り上げます。セットビットとは、数値を2進数で表したときに「1」となっているビットのことです。セットビット数が多い要素ほど、少ない要素よりも前に配置されるように並べ替えます。例として、12・15・7 という3つの数値を考えてみましょう。それぞれの2進数表現とセットビット数は次のとおりです。1100 (12) → セットビット数 21111 (15) → セットビット数 40111 (7) → セットビット数 3これをセットビット数の降順でソートすると、結果は以下のようになります。1111, 0111, 1100 (つま
-
C++でk個のセットビットを持つ数を最大化するために必要な最小フリップ回数
問題文2つの整数 n と k が与えられます。n のビットを反転(フリップ)して、結果の数がちょうど k 個のセットビット(値が1のビット)を持ち、かつ取り得る最大の数になるようにするために必要な、最小のフリップ回数を求めてください。なお、入力は「k が n のビット数より小さい」という条件を満たす必要があります。例n = 9、k = 2 とします。9 の2進表現は 1001 であり、4ビットで構成されています。4桁の2進数の中でセットビットが2個となる最大の数は 1100、すなわち10進数の 12 です。1001 を 1100 に変換するには、2ビットを反転する必要があります。アルゴリズム1