C++で0と1の個数が等しい最長の連続部分配列を求める方法
問題概要
0と1のみから構成されるバイナリ配列が与えられたとき、0と1の個数が等しい連続する部分配列(サブ配列)の最大長を求めることを考えます。
例えば、入力が [0,1,0] の場合、出力は 2 になります。[0,1] または [1,0] が、0と1の個数が等しい最長の連続部分配列だからです。
解法のアプローチ
この問題は「累積和」とハッシュマップを組み合わせることで効率的に解けます。1を +1、0を −1 として扱い、同じ累積和が2回現れた位置の間に、0と1の個数が等しい区間が存在すると考えるのがポイントです。
具体的な手順は以下の通りです。
ret := 0(答え)、n := numsのサイズ、sum := 0(累積和)で初期化します。- マップ
mを作成し、m[0] := -1を設定します(配列の先頭より前を表す番兵です)。 - i を 0 から numsのサイズ − 1 までループさせます。
nums[i]が 1 ならsum := sum + 1、そうでなければsum := sum − 1とします。sumがすでにマップmに存在する場合、ret := max(ret, i − m[sum])で答えを更新します。存在しない場合はm[sum] := iとして現在位置を記録します。
- 最後に
retを返します。
同じ累積和が再び現れたということは、その間の区間で +1 と −1 の加算が打ち消し合ったことになり、すなわち0と1の個数が等しいことを意味します。この手法により、計算量は O(n) と非常に効率的になります。
C++での実装例
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int ret = 0;
int n = nums.size();
int sum = 0;
map <int, int> m;
m[0] = -1;
for(int i = 0; i < nums.size(); i++){
sum += nums[i] == 1 ? 1: -1;
if(m.count(sum)){
ret = max(ret, i - m[sum]);
}else m[sum] = i;
}
return ret;
}
};
main(){
vector<int> v = {0,1,0,0,1};
Solution ob;
cout << (ob.findMaxLength(v));
}
入力
[0,1,0,0,1]
出力
4
この例では、[0,1,0,0,1] の中で [0,1,0,1](インデックス0〜3)が0と1の個数が等しい最長の連続部分配列となるため、出力は 4 になります。
-
C++で配列を並べ替える方法|選択ソートの仕組みと実装例を解説
C++では、さまざまなソート(並べ替え)アルゴリズムを使って配列を整列できます。ソート済みの配列とは、数値の大小順やアルファベット順など、何らかの基準に従って要素が並び替えられた配列のことです。代表的なソートアルゴリズムには、バブルソート、挿入ソート、選択ソート、マージソート、クイックソート、ヒープソートなどがあります。本記事では、その中でも構造がシンプルで理解しやすい「選択ソート」を取り上げ、実際のコード例とともに詳しく解説していきます。 選択ソートとは? 選択ソートは、未ソート部分の中から最小値を繰り返し探し出し、それを未ソート部分の先頭にある要素と交換することで、配列全体を昇順に整列さ
-
C++でポインタ演算を使って配列要素の合計を求める方法
この記事では、C++においてポインタ演算を利用して配列要素の合計を求めるプログラムを紹介します。C++では配列名は先頭要素へのポインタとして扱えるため、*(ptr + i) のように記述することで、添字演算子を使わずに各要素へアクセスできます。 アルゴリズム 開始 ユーザーからの入力値で配列要素を初期化する 合計を格納する変数 s を 0 で初期化する i = 0 から 6 まで繰り返す s = s + *(ptr + i) 変数 s に格納された合計値を出力する 終了 サンプルコード #include<iostream> using