C++で解く「美しい配列」問題:等差条件を回避する順列の構築アルゴリズム
固定した値 N に対して、配列 A が「美しい(beautiful)」とは、A が 1, 2, ..., N の順列であり、かつ次の条件を満たすことを意味します。
任意の i < j について、i < k < j を満たし、かつ A[k] * 2 = A[i] + A[j] となる k は存在しない。
言い換えると、インデックスの順序において、両端の要素の平均値が中央の要素と一致するような3つの要素の組み合わせが一切現れてはいけない、という制約です。N が与えられたとき、この条件を満たす美しい配列 A を1つ構築するのが本問題の目的です。
たとえば入力が 5 の場合、出力は [3,1,2,5,4] のようになります。
解法のアプローチ
この問題は、配列を「奇数」と「偶数」に分けながら段階的に拡張していく手法で解くことができます。具体的な手順は以下の通りです。
配列 ret を作成し、初期値として 1 を挿入します。
ret のサイズが N 未満である間、次の処理を繰り返します。
新しい配列 temp を用意します。
ret の各要素 x に対して、x * 2 - 1(奇数)が N 以下であれば temp に挿入します。
続けて、各要素 x に対して、x * 2(偶数)が N 以下であれば temp に挿入します。
ret を temp で更新します。
最終的な ret を結果として返します。
なぜこの手法が機能するのか
条件式 A[k] * 2 = A[i] + A[j] が成立するには、A[i] + A[j] が偶数である必要があります。つまり、A[i] と A[j] が同じ偶奇(パリティ)を持つ場合にしか成り立ちません。
上記の構成法では、配列の前半にすべての奇数を、後半にすべての偶数を配置します。そのため、奇数領域と偶数領域をまたぐ i < j のペアでは、2つの値の和が必ず奇数となり、条件を満たすことができません。一方、奇数同士・偶数同士のペアについては、各ステップで元の配列の相対的な順序と構造が保たれるため、帰納的に条件が維持されます。この性質により、全体として美しい配列が得られます。
C++による実装例
#include <bits/stdc++.h>
using namespace std;
void print_vector(vector<auto> v){
cout << "[";
for(int i = 0; i<v.size(); i++){
cout << v[i] << ", ";
}
cout << "]"<<endl;
}
class Solution {
public:
vector<int> beautifulArray(int N) {
vector<int> ret;
ret.push_back(1);
while(ret.size() < N){
vector<int> temp;
for(int i = 0; i < ret.size(); i++){
if(ret[i] * 2 - 1 <= N) temp.push_back(ret[i] * 2 - 1);
}
for(int i = 0; i < ret.size(); i++){
if(ret[i] * 2 <= N) temp.push_back(ret[i] * 2);
}
ret = temp;
}
return ret;
}
};
main(){
Solution ob;
print_vector(ob.beautifulArray(5));
}
入力
5
出力
[1,5,3,2,4]
この実装では、反復のたびに配列のサイズがほぼ2倍に増加していくため、全体の計算量は O(N log N) 程度に収まります。そのため、比較的大きな N に対しても効率的に美しい配列を生成できる点が大きな特徴です。
-
C++で解く「ジャンプゲームV」:メモ化再帰による最大訪問インデックス数の求め方
問題の概要整数型の配列 arr と整数 d が与えられます。1ステップごとに、インデックス i から次の場所へジャンプできます。右方向: i + x(ただし i + x < n、かつ x は 1 以上 d 以下)左方向: i - x(ただし i - x >= 0、かつ x は 1 以上 d 以下)ここで n は配列のサイズです。さらに重要な制約として、インデックス i から j へジャンプできるのは、arr[i] > arr[j] であり、かつ i と j の間にあるすべてのインデックス k に対して arr[i] > arr[k] を満たす場合のみです。つまり、より低
-
C++で配列を並べ替える方法|選択ソートの仕組みと実装例を解説
C++では、さまざまなソート(並べ替え)アルゴリズムを使って配列を整列できます。ソート済みの配列とは、数値の大小順やアルファベット順など、何らかの基準に従って要素が並び替えられた配列のことです。代表的なソートアルゴリズムには、バブルソート、挿入ソート、選択ソート、マージソート、クイックソート、ヒープソートなどがあります。本記事では、その中でも構造がシンプルで理解しやすい「選択ソート」を取り上げ、実際のコード例とともに詳しく解説していきます。 選択ソートとは? 選択ソートは、未ソート部分の中から最小値を繰り返し探し出し、それを未ソート部分の先頭にある要素と交換することで、配列全体を昇順に整列さ