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

C++で整数をエンコードするアルゴリズムの実装方法

非負整数 n が与えられたとき、そのエンコード形式を求めることを考えます。エンコードのルールは以下の表の通りです。

数値エンコード結果
0""
1"0"
2"1"
3"00"
4"01"
5"10"
6"11"
7"000"

表を見ると、1桁の「0」「1」は数値1・2に、2桁の「00」〜「11」は数値3〜6に、3桁の「000」以降は数値7以降に対応していることが分かります。つまり、ビット長ごとに区切られたブロックの中へ、整数が順番に割り当てられていく仕組みです。

たとえば、数値が23であれば結果は「1000」、数値が54であれば「10111」になります。

解き方の手順

この問題を解くには、次の手順に従います。

  • まず、n と k を受け取る bin メソッドを作成します。このメソッドは以下のように動作します。
  • res := 空文字列
  • n > 0 の間、次を繰り返す
    • res := res + (n を 2 で割った余りの数字)
    • n := n / 2
  • res を反転する
  • x > res の長さ である間、res の先頭に「0」を付け足す
  • res を返す

続いて、本体となるメソッドは次の通りです。

  • n = 0 なら空文字列を、n = 1 なら「0」を、n = 2 なら「1」を返す
  • x := log₂(n)(2を底とした対数)
  • もし 2^(x+1) - 1 = n ならば
    • ans := 空文字列
    • x を 1 増やして、x 回だけ ans の末尾に「0」を追加する
    • ans を返す
  • それ以外の場合は bin(n - 2^x + 1, x) を返す

ここで、2^(x+1) - 1 という条件は「n + 1 が2のべき乗になっているか」、つまり新しいビット長のブロックの先頭に来ているかどうかを判定しています。該当する場合はすべて「0」の文字列が答えとなり、それ以外の場合はブロック内の位置を2進数に変換して桁数を揃える、という流れです。

理解を深めるために、以下の実装例を見てみましょう。

実装例

#include <bits/stdc++.h>
using namespace std;
class Solution {
    public:
    string bin(int n, int x){
        string result = "";
        while(n>0){
            result += (n%2) + '0';
            n/=2;
        }
        reverse(result.begin(), result.end());
        while(x>result.size())result = '0' + result;
        return result;
    }
    string encode(int n) {
        if(n == 0)return "";
        if(n == 1)return "0";
        if(n==2) return "1";
        int x = log2(n);
        if(((1<<(x+1)) - 1) == n){
            string ans = "";
            x++;
            while(x--)ans+="0";
            return ans;
        }
        return bin(n - (1<<x) + 1, x);
    }
};
main(){
    Solution ob;
    cout << (ob.encode(23)) << endl;
    cout << (ob.encode(54)) << endl;
}

入力

23
54

出力

1000
10111

まとめ

このエンコード方式では、2^k - 1 以上 2^(k+1) - 2 以下の整数が、すべて k 桁の2進文字列へ順に対応付けられます。encode 関数では log₂(n) によって所属ブロックの桁数 x を求め、ブロックの先頭(n = 2^(x+1) - 1)であれば (x+1) 個の「0」を返し、それ以外ではブロック内の位置を表す n - 2^x + 1 を2進変換し、bin 関数で x 桁になるよう先頭を0で埋めた文字列を返します。処理は対数オーダーで完了するため、大きな n に対しても高速に動作するのが特徴です。

  1. C++で質素数(Frugal Number)を判定する方法【サンプルコード付き】

    この記事では、正の整数 N が与えられたときに、その数が質素数(Frugal Number)であるかどうかを判定するプログラムを C++ で作成する方法を解説します。 質素数とは? 質素数(FRUGAL NUMBER)とは、その数自身の桁数が、素因数分解による表現の桁数よりも厳密に大きい数のことです。 例:625 の場合 625 を素因数分解すると 54 となります。 625 自身の桁数:3 桁 54 の表現の桁数:2 桁 3 は 2 よりも厳密に大きいため、625 は質素数です。 最初のいくつかの質素数:125、128、243、256、343、512、625 など 問題を理解するための具

  2. C++で五胞体数(ペンタトープ数)を求める方法

    五胞体数とは? 五胞体数(ペンタトープ数)は、パスカルの三角形の第5の対角線上に現れる数列として知られています。この数列を定義するには、パスカルの三角形に少なくとも5つの数が必要となるため、数列の最初の数はパスカルの三角形の第4行である 1 4 6 4 1 から始まります。 本チュートリアルでは、n番目の五胞体数を求める方法を解説します。まずは具体的な例を見てみましょう。 入力 : 1出力 : 1入力 : 4出力 : 35 以下の図から出力を確認できます。 この問題は数列に関するものなので、解法ではまず数列のパターンを見つけることから始めます。 解法のアプローチ このプログラムでは、数列の