C++で解く「2倍ペアに並べ替えられるか」判定アルゴリズム
問題概要
長さが偶数の整数配列 A が与えられます。この配列を並べ替えることで、すべての 0 <= i < len(A) / 2 について A[2 * i + 1] = 2 * A[2 * i] が成り立つようにできる場合のみ true を返します。
例えば、入力が [3, 1, 3, 6] の場合は false を返し、[4, -2, 2, -4] の場合は true を返します。後者は [-2, -4] と [2, 4] というペアに分けられるためです。
解き方の考え方
この問題は、各要素の出現回数を記録したマップ(連想配列)を使って、小さい値から順に「自分の2倍の値」とマッチングさせていくことで解けます。手順は以下の通りです。
- マップ m を作成し、配列 A の各要素の出現回数を格納する
- cnt := 配列 A のサイズとする(まだ処理されていない要素数)
- マップ内の各キーと値のペア kv について以下を繰り返す
- m[kv.key] > 0 の場合:
- kv.key が 0 ではなく、かつ m[2 * kv.key] > 0 であれば、x := min(m[kv.key], m[2 * kv.key]) として、cnt から x * 2 を引き、両方のカウントから x を減らす
- kv.key が 0 の場合は、0 同士がペアになるため cnt から m[0] を引いて m[0] を 0 にする
- m[kv.key] > 0 の場合:
- 最終的に cnt が 0 でなければ false、0 なら true を返す
std::map はキーが昇順にソートされるため、負の値から順に処理される点にも注意してください。負の数の場合、2倍するとより小さい値になるため、昇順処理によって正しくペアリングできます。
C++実装例
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
bool canReorderDoubled(vector<int>& A) {
map <int, int> m;
int n = A.size();
for(int i = 0; i < n; i++){
m[A[i]]++;
}
int cnt = A.size();
map <int, int> :: iterator it = m.begin();
while(it != m.end()){
if(m[it->first] > 0){
if(it->first != 0 && m[it->first * 2] > 0){
int x = min(m[it->first], m[it->first * 2]);
cnt -= (x * 2);
m[it->first * 2] -= x;
m[it->first] -= x;
}else if(it->first == 0){
cnt -= m[it->first];
m[it->first] = 0;
}
}
it++;
}
return !cnt;
}
};
main(){
vector<int> v1 = {3,1,3,6};
Solution ob;
cout << (ob.canReorderDoubled(v1)) << endl;
v1 = {4,-2,2,-4};
cout << (ob.canReorderDoubled(v1));
}入力
[3,1,3,6] [4,-2,2,-4]
出力
0 1
最初の入力 [3,1,3,6] では、6 の半分である 3 は存在しますが、3 の半分や 6 の2倍に対応する要素が足りず、すべてをペアにできないため 0(false)が出力されます。一方、[4,-2,2,-4] では -2 → -4 と 2 → 4 のペアが成立するため 1(true)が出力されます。
計算量
時間計算量は O(n log n)(マップへの挿入と走査)、空間計算量は O(n) となります。
-
C++で文字列の配列を定義・操作する方法を解説
この記事では、C++において文字列の配列をどのように定義し、扱うのかを詳しく解説します。C言語との違い:文字列配列の基礎知識C言語には文字列型が存在しないため、文字列はchar型の配列(文字配列)として表現する必要がありました。そのため、複数の文字列をまとめて管理する「文字列の配列」を作るには、2次元のchar型配列を用意し、各行に異なる文字列を格納するという手法が取られていました。これは直感的ではなく、コードも冗長になりがちでした。一方、C++ではstd::stringクラスが標準ライブラリとして提供されています。このクラスのオブジェクトを使えば、文字列データを効率的かつ安全に格納・操作でき
-
C++で配列を並べ替える方法|選択ソートの仕組みと実装例を解説
C++では、さまざまなソート(並べ替え)アルゴリズムを使って配列を整列できます。ソート済みの配列とは、数値の大小順やアルファベット順など、何らかの基準に従って要素が並び替えられた配列のことです。代表的なソートアルゴリズムには、バブルソート、挿入ソート、選択ソート、マージソート、クイックソート、ヒープソートなどがあります。本記事では、その中でも構造がシンプルで理解しやすい「選択ソート」を取り上げ、実際のコード例とともに詳しく解説していきます。 選択ソートとは? 選択ソートは、未ソート部分の中から最小値を繰り返し探し出し、それを未ソート部分の先頭にある要素と交換することで、配列全体を昇順に整列さ