C++でソート済み配列に含まれる余分な要素のインデックスを見つける方法
この問題では、サイズ n と n+1 の2つのソート済み配列 arr1 と arr2 が与えられます。両配列の要素は、余分な要素を除いてすべて同じです。私たちのタスクは、ソート済み配列の一方に存在する余分な要素のインデックスを見つけることです。
問題の説明: サイズ n+1 の配列に存在し、サイズ n の配列には存在しない要素のインデックスを求める必要があります。
問題を理解するための例
入力: arr1[n] = {3, 5, 7, 8, 9, 12}
arr2[n+1] = {3, 4, 5, 7, 8, 9, 12}
出力: 1
説明:
値が 4 の要素が余分な要素であり、そのインデックスは 1 です。
解決アプローチ
最もシンプルな解決策は、「両方の配列がソートされている」という性質を利用する方法です。異なる要素は1つだけであるため、線形探索を行うことで、arr1[] に存在しない arr2 の要素を簡単に見つけることができます。
アルゴリズム:
ステップ1: i を 0 から n+1 までループさせる。
ステップ1.1: 異なる要素、つまり arr1[i] != arr2[i] となる要素を見つけたら、ループを抜ける。
ステップ2: i の値を返す。
解決策の動作を示すプログラム
例
#include <iostream>
using namespace std;
int findExtraElement(int arr1[], int arr2[], int n) {
int i;
for (i = 0; i < n; i++)
if (arr1[i] != arr2[i])
break;
return i;
}
int main()
{
int arr1[] = {3, 5, 7, 8, 9, 12};
int arr2[] = {3, 4, 5, 7, 8, 9, 12};
int n = sizeof(arr1) / sizeof(arr1[0]);
int extraIndex = findExtraElement(arr1, arr2, n);
cout<<"The extra element is at index ("<<extraIndex<<") and the value is "<<arr2[extraIndex];
return 0;
}
出力
The extra element is at index (1) and the value is 4
この解決策は、線形探索の代わりに、より効率的な探索手法である二分探索(バイナリサーチ)を使用することで改善できます。二分探索では、配列の中央にある要素同士を比較し、一致していれば探索範囲を右半分に、一致していなければ左半分に絞り込んでいくため、O(log n) の時間計算量で余分な要素を見つけることができ、アルゴリズムの計算時間を大幅に短縮できます。
二分探索を使った解決策のプログラム
例
#include <iostream>
using namespace std;
int findExtraElement(int arr1[], int arr2[], int n) {
int extraIndex = n;
int start = 0, end = n - 1;
while (start <= end)
{
int mid = (start + end) / 2;
if (arr2[mid] == arr1[mid])
start = mid + 1;
else
{
extraIndex = mid;
end = mid - 1;
}
}
return extraIndex;
}
int main()
{
int arr1[] = {3, 5, 7, 8, 9, 12};
int arr2[] = {3, 4, 5, 7, 8, 9, 12};
int n = sizeof(arr1) / sizeof(arr1[0]);
int extraIndex = findExtraElement(arr1, arr2, n);
cout<<"The extra element is at index ("<<extraIndex<<") and the value is "<<arr2[extraIndex];
return 0;
}
出力
The extra element is at index (1) and the value is 4
別のアプローチ:合計の差を利用する方法
もう一つの解決方法として、2つの配列の合計値の差を求めるアプローチがあります。この差の絶対値こそが余分な要素の値です。次に、サイズ n+1 の配列の中から探索アルゴリズムを使ってこの余分な要素のインデックスを見つけます。この方法の時間計算量は O(n) となります。
合計の差を利用した解決策のプログラム
例
#include <iostream>
using namespace std;
int calcArraysum(int arr[], int n){
int sum = 0;
for(int i = 0; i < n; i++)
sum += arr[i];
return sum;
}
int findExtraElement(int arr1[], int arr2[], int n) {
int extraValue = calcArraysum(arr2, n+1) - calcArraysum(arr1, n);
for (int i = 0; i < n; i++)
{
if (arr2[i] == extraValue)
return i;
}
return -1;
}
int main()
{
int arr1[] = {3, 5, 7, 8, 9, 12};
int arr2[] = {3, 4, 5, 7, 8, 9, 12};
int n = sizeof(arr1) / sizeof(arr1[0]);
int extraIndex = findExtraElement(arr1, arr2, n);
cout<<"The extra element is at index ("<<extraIndex<<") and the value is "<<arr2[extraIndex];
return 0;
}
出力
The extra element is at index (1) and the value is 4
-
C++で回転ソート済み配列の回転回数を求める方法
ここでは、回転ソート済み配列(Rotated Sorted Array)が与えられたときに、その配列を元のソートされた状態に戻すために必要な回転回数を求める問題を扱います。なお、回転は「右から左へ」要素を移動させる操作として考えます。例えば、次のような配列を考えてみましょう。{15, 17, 1, 2, 6, 11}この配列をソートするには、2回の回転が必要です。回転を繰り返すと、最終的に次の順序になります。{1, 2, 6, 11, 15, 17}この場合の出力(回転回数)は 2 となります。解法のポイントこの問題のロジックは非常にシンプルです。配列を注意深く観察すると、必要な回転回数は「最
-
C++で配列内の各要素のサーパッサー(Surpasser)の数を求めるアルゴリズム
ある配列Aが与えられたとき、各要素の「サーパッサー(surpasser)」の数を求める問題を考えてみましょう。サーパッサーとは、現在注目している要素よりも右側に存在する、その要素より大きい値のことです。 例えば、A = {2, 7, 5, 3, 0, 8, 1} という配列の場合、サーパッサーの数は {4, 1, 1, 1, 2, 0, 0} となります。これは、先頭の「2」の右側には「7・5・3・8」という4つの大きな値が存在するためです。その他の要素についても同じルールで数えていきます。 アルゴリズムの考え方 解法は非常にシンプルです。2重のループを使用し、外側のループで各要素を順に取り上