C++で配列をK個の連続する整数のセットに分割できるか判定する方法
問題概要
整数型の配列 nums と正整数 k が与えられます。この配列を「連続する k 個の整数」からなるセットに完全に分割できるかどうかを判定し、可能であれば true を、不可能であれば false を返してください。
たとえば、入力が [1,2,3,3,4,4,5,6]、k = 4 の場合を考えてみましょう。この配列は [1,2,3,4] と [3,4,5,6] の2つのセットに分割できるため、答えは true(出力は 1)になります。
解法のアプローチ
この問題は、マップ(連想配列)で各数値の残り出現回数を管理しながら、昇順にグループを形成していくことで効率よく解けます。手順は以下の通りです。
- マップ
mを用意し、nを配列numsのサイズとします。 numsの各要素eについてm[e]を1増やし、出現回数を記録します。- 消費済み要素数を数える変数
cntを 0 で初期化します。 - 配列
numsを昇順にソートします。 - i が 0 から n-1 までの範囲で以下を繰り返します。
x := nums[i]とします。m[x - 1] == 0かつm[x] > 0の場合、x は新しいグループの先頭候補です。長さ k のグループ構築を試みます。l := kとして現在の k を退避します。- k > 0 の間、次を繰り返します。
m[x] > 0であればm[x]を1減らします。該当する数が残っていなければ即座にfalseを返します。その後、x を1増やし、cnt を1増やし、k を1減らします。 - グループ構築後、
k := lとして元の値に戻します。
- 最後に、
cnt == nであればtrueを、そうでなければfalseを返します。
ポイントは、ソート済みの配列を先頭から走査し、「直前の数(m[x-1])が残っていない」要素だけをグループの始点として扱うことです。これにより、すべての数が必ずどこかの連続シーケンスに割り当てられ、途中で必要な連続する数が不足すれば分割不可能と判断できます。
C++による実装例
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
bool isPossibleDivide(vector<int>& nums, int k) {
map<int, int> m;
int n = nums.size();
for(int i = 0; i < n; i++){
m[nums[i]]++;
}
int cnt = 0;
sort(nums.begin(), nums.end());
for(int i = 0; i < n; i++){
int x = nums[i];
if(m[x - 1] == 0 && m[x] > 0){
int l = k;
while(k > 0){
if(m[x] > 0){
m[x]--;
} else return false;
x++;
k--;
cnt++;
}
k = l;
}
}
return cnt == n;
}
};
main(){
vector<int> v = {1,2,3,3,4,4,5,6};
Solution ob;
cout << (ob.isPossibleDivide(v, 4));
}
入力例
[1,2,3,3,4,4,5,6] 4
出力例
1
計算量
ソートに O(n log n) かかり、その後の走査では各要素が定数回ずつ処理されるため、全体の時間計算量は O(n log n) です。マップの各操作も O(log n) であるため、合計でも O(n log n) に収まります。空間計算量はマップの分の O(n) です。
-
C++で循環配列内の連続する1(または0)の最大数を求める方法
本記事では、循環配列(サーキュラー配列)を扱います。循環配列とは、最初の要素が最後の要素の直後に続くものとみなす配列のことで、キューの実装などによく利用されます。ここでは、このような配列の中で連続して現れる「1」または「0」の最大個数を数える方法を解説します。 具体的な例で確認してみましょう。 入力 − Arr[] = { 1,1,0,1,0,1,0,1,1,1 } 出力 − 連続する「1」の最大数は5。連続する「0」の最大数は1。 説明 − 配列のインデックス7から9、さらにインデックス0と1にまたがって「1」が5個連続しています。一方、「0」は連続して現れず、最大でも1個です。 入力 −
-
【C++】配列内のすべての素数の積を求める方法
整数型配列 arr[] が与えられたとき、その配列に含まれるすべての素数を見つけ出し、それらの積を計算するのが本記事のテーマです。素数とは、1とその数自身でしか割り切れない正の整数のことです。たとえば、2、3、5、7、11などが素数に該当します。それでは、次の配列を例に解を求めてみましょう。入力: arr[] = { 11, 20, 31, 4, 5, 6, 70 }出力: 1705説明: 配列内の素数は 11、31、5 の3つであり、その積は 11 × 31 × 5 = 1705 となります。入力: arr[] = { 1, 2, 3, 4, 5, 6, 7 }出力: 210説明: 配列内の