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

C++で数値の2進表現に含まれる長さn以上の連続する「1」を検索する方法

問題の概要

2つの整数 x と n が与えられたとき、32ビットの2進表現の中から「長さが n 以上となる最初の連続した1の並び」を探し、その開始位置を返すことを考えます。該当する並びが存在しない場合は -1 を返します。

例えば、x = 35、n = 2 の場合、結果は 31 になります。32ビット整数としての 35 の2進表現は以下のとおりです。

00000000000000000000000000100011

この中で2つの「1」が連続して現れているのはインデックス31の位置なので、答えは 31 となります。

解決のアプローチ

この問題を解くポイントは、「先頭の0(リーディングゼロ)の個数」を求めることです。先頭の0の数をもとに、連続する「1」の並びを順番に特定していきます。処理の流れは以下のとおりです。

  1. x の先頭にある0の個数を数え、その分だけ左シフトすることで、最初の「1」を最上位ビットの位置まで移動させます。
  2. 次に、ビットを反転した値(~x)の先頭にある0の個数を調べます。この値は、直前に見つかった連続する「1」の長さに対応します。
  3. その長さが n 以上であれば現在位置を結果として返します。条件を満たさない場合はさらに左シフトを行い、x が0になるまで同様の処理を繰り返します。

C++による実装例

#include<iostream>
using namespace std;
int leadingZeroCount(int x) {
    unsigned y;
    int n;
    n = 32;
    for(int i = 16; i > 1; i = i/2 ){
        y = x >> i;
        if(y != 0){
            n -= i;
            x = y;
        }
    }
    y = x >> 1;
    if (y != 0)
        return n - 2;
    return n - x;
}
int consecutiveOnePosition(unsigned x, int n) {
    int k, p;
    p = 0;
    while (x != 0) {
        k = leadingZeroCount(x);
        x = x << k;
        p = p + k;
        k = leadingZeroCount(~x);
        if (k >= n)
            return p + 1;
        x = x << k;
        p = p + k;
    }
    return -1;
}
int main() {
    int x = 35;
    int n = 2;
    cout << "Consecutive 1s of length " << n << " is starting from index: " << consecutiveOnePosition(x, n);
}

実行結果

Consecutive 1s of length 2 is starting from index: 31

この実行結果から、x = 35 の場合、長さ2以上の連続する「1」はインデックス31から始まっていることが確認できます。リーディングゼロのカウントとビットシフトを組み合わせることで、効率よく連続する「1」の並びを検索できるのがこのアルゴリズムの特徴です。

  1. C++で解く!Nの階乗のB進表現における末尾ゼロの個数の求め方

    はじめにこの記事では、与えられた数Nの階乗(N!)を基数Bで表したとき、末尾にいくつのゼロが連続するかを求める問題について詳しく解説します。問題の例入力 : N = 7、基数 = 2 出力 : 4 説明 : fact(7) = 5040(10進数)であり、2進数では「1001110110000」となるため、末尾にゼロが4個並びます。 入力 : N = 11、基数 = 5 出力 : 2 説明 : fact(11) = 39916800(10進数)であり、5進数では「40204314200」となるため、末尾にゼロが2個並びます。基数変換のおさらいまず、10進数から他の基数へ数値を変換する手順を確

  2. C++で解く!Nの階乗の16進数表現における末尾のゼロの個数の求め方

    この記事では、与えられた整数Nの階乗(N!)を16進数で表したとき、末尾に何個のゼロが連続するかを求める問題について詳しく解説します。 入力 : N = 7 出力 : 1 説明 : fact(7) = 5040(10進数)で、16進数では13B0となり、末尾のゼロは1個です。 入力 : N = 11 出力 : 2 説明 : fact(11) = 39916800(10進数)で、16進数では2611500となり、末尾のゼロは2個です。 10進数から16進数への変換のおさらい まず、任意の10進数を別の基数へ変換する手順をおさらいしましょう。ここでは、(5040)10 を16進数に変換する例を