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

C++で1つおきの要素を削除した後、最後に残る要素を求めるアルゴリズム

問題の概要

1からnまでの整数が格納された循環配列を考えます。最初の要素から数え始め、2つおきに要素を削除していったとき、最後に残る要素を求めるのがこの問題です。例えば、入力が5の場合、配列は [1, 2, 3, 4, 5] となります。1から開始して2つおきに削除を進めると、配列の状態は以下のように変化します。

1 0 3 4 5
1 0 3 0 5
0 0 3 0 5
0 0 3 0 0

この結果、最後まで残る要素は 3 であることがわかります。

再帰を使った解法

この問題は、再帰的な漸化式を用いることで効率的に解くことができます。

まず、nが偶数の場合を考えてみましょう。1周目で 2, 4, 6, ... という偶数がすべて削除され、その後は再び 1 から数え始めます。つまり、n/2 個の要素が削除された後の状態は、「1, 3, 5, ... という奇数だけからなる長さ n/2 の配列で、1 から数え始める」状況とまったく同じです。新しい配列の i 番目の要素は元の配列の 2i−1 番目に対応するため、次の漸化式が成り立ちます。

一方、nが奇数の場合は、1周目で 2, 4, ..., n−1 が削除された後、さらに 1 が削除され、「3, 5, ..., n からなる長さ (n−1)/2 の配列で、3 から数え始める」状況になります。これらの性質から、以下の漸化式が導けます。

solve(n) = 2 * solve(n / 2) - 1        (n が偶数の場合)
solve(n) = 2 * solve((n - 1) / 2) + 1  (n が奇数の場合)

再帰の基本条件(ベースケース)は solve(1) = 1 です。

C++での実装例

#include <iostream>
using namespace std;

int deleteSecondElement(int n) {
    if (n == 1)
        return 1;
    if (n % 2 == 0)
        return 2 * deleteSecondElement(n / 2) - 1;
    else
        return 2 * deleteSecondElement((n - 1) / 2) + 1;
}

int main() {
    int n = 5;
    cout << "Remaining Element: " << deleteSecondElement(n) << endl;

    n = 10;
    cout << "Remaining Element: " << deleteSecondElement(n) << endl;

    return 0;
}

実行結果

Remaining Element: 3
Remaining Element: 5

計算量

このアルゴリズムは、再帰呼び出しのたびに問題のサイズが半分になるため、時間計算量は O(log n) です。また、再帰スタックの深さも O(log n) であるため、空間計算量も O(log n) となります。

  1. C++で配列内の各要素に最も近い大きい値を効率的に検索する方法

    この記事では、配列内の各要素に対して「最も近い大きい値」を効率的に検索する方法を解説します。ある要素 x より大きい値が配列内に存在する場合、その中で最も小さい値(次に大きい要素)をその要素の答えとし、存在しない場合は -1 を出力します。例として、配列が {10, 5, 11, 10, 20, 12} の場合、結果は {11, 10, 12, 11, -1, 20} となります。最大値の 20 より大きい要素は配列内に存在しないため、20 に対しては -1 が出力されます。解決のアプローチこの問題は C++ STL の set(セット)を使うと簡単に解決できます。set は二分探索木をベース

  2. C++で配列の最大要素とその位置を見つける方法

    配列の最大要素とは配列には複数の要素が格納されており、その中で他のすべての要素よりも大きい値を持つものが「最大要素」です。具体例51724上記の配列の場合、最大要素は7であり、インデックス2の位置に存在します。それでは、配列の最大要素を求めるC++プログラムを見ていきましょう。サンプルコード#include <iostream> using namespace std; int main() { int a[] = {4, 9, 1, 3, 8}; int largest, i, pos; largest = a[0]; for(i=1; i<