Pythonで1〜Nの範囲の配列から欠落している4つの数を検索する方法
問題の概要
ここでは、1からNまでの範囲に属する相異なる整数で構成された配列を扱います。配列のサイズは N-4 であり、要素の重複は一切ありません。つまり、1からNまでのうち4つの数が配列から抜け落ちていることになります。この記事では、その4つの欠落数を昇順で特定する方法を解説します。
例として、入力が A = [2, 8, 4, 13, 6, 11, 9, 5, 10] の場合、出力は [1, 3, 7, 12] となります。
アルゴリズムのポイント
この問題は、追加のメモリをほとんど使わずに解決できます。鍵となるのは「符号反転」のテクニックです。配列内の値 v に対応する位置(インデックス v-1)にある要素の符号を反転させることで、「v は出現済み」というマークを付けます。処理後に正の値が残っている位置こそが、欠落している数を表しています。
また、N が配列の長さを超える場合(本記事のように N = 配列サイズ + 4 のケース)は、サイズ4の補助配列を用意し、剰余演算を活用して後半の数値の出現情報を記録します。
処理の手順
- すべて0で初期化されたサイズ4の補助配列
temp_arrを用意する。 - i を 0 から配列 A のサイズ未満まで繰り返す。
temp := |A[i]|として絶対値を取得する。- temp が A のサイズ以下の場合:
A[temp - 1]の符号を反転する。 - temp が A のサイズより大きい場合:
- temp を A のサイズで割った余りが0でなければ、
temp_arr[temp % len(A) - 1]を -1 にする。 - 余りが0の場合は、
temp_arr[(temp % len(A)) + len(A) - 1]を -1 にする。
- temp を A のサイズで割った余りが0でなければ、
- i を 0 から A のサイズ未満まで繰り返し、
A[i] > 0ならi + 1を表示する。 - i を 0 から temp_arr のサイズ未満まで繰り返し、
temp_arr[i] >= 0ならlen(A) + i + 1を表示する。
最初のループで小さい側の欠落数が、次のループで大きい側の欠落数がそれぞれ昇順に出力されるため、結果全体も自然にソートされた順序になります。
実装例
理解を深めるために、以下のPythonコードを見てみましょう。
def find_missing_nums(A) :
temp_arr = [0]*4
for i in range(0,len(A)) :
temp = abs(A[i])
if (temp <= len(A)) :
A[temp - 1] = A[temp - 1] * (-1)
elif (temp > len(A)) :
if (temp % len(A)) :
temp_arr[temp % len(A) - 1] = -1
else :
temp_arr[(temp % len(A)) +len(A) - 1] = -1
for i in range(0, len(A) ) :
if (A[i] > 0) :
print((i + 1) , end=" ")
for i in range(0, len(temp_arr)) :
if (temp_arr[i] >= 0) :
print((len(A) + i + 1) , end=" ")
A = [2, 8, 4, 13, 6, 11, 9, 5, 10]
find_missing_nums(A)入力
[2, 8, 4, 13, 6, 11, 9, 5, 10]出力
1 3 7 12計算量と注意点
このアルゴリズムは配列を数回走査するだけで済むため、時間計算量は O(N) です。追加で必要なメモリもサイズ4の補助配列のみであり、ソート処理やハッシュセットに頼らずに欠落数を求められる点が大きな特徴です。
ただし、この手法は元の配列の要素の符号を直接書き換えるため、入力データを後続の処理でも使いたい場合は、あらかじめ配列をコピーしておくことをおすすめします。
-
【初心者向け】Pythonでリストのサイズ(要素数)を取得する方法
リスト(list)は、Pythonにおける代表的なコレクション型のデータ構造の一つです。リストの要素は後から変更でき、重複した値を持つこともできます。本記事では、Pythonでリストのサイズ(長さ)を取得する方法を解説します。具体的には、重複の有無にかかわらず、リストに含まれる全要素の数をカウントする方法を紹介します。リストの長さを取得する基本:len()関数Pythonでリストの要素数を取得するには、組み込み関数の len() を使用します。len() はリストだけでなく、タプル・文字列・辞書などさまざまなコレクションに対しても利用できる汎用的な関数です。サンプルコード以下の例では、「day
-
PythonでリストからN個の最大要素を取得する方法
整数のリストが与えられたとき、その中からN個の大きな要素を取り出して新しいリストとして返すのが、ここでの課題です。本記事では、基本的なループ処理による方法から、Python標準ライブラリを活用した効率的な方法まで、サンプルコードとともに解説します。 例 入力 : [40, 5, 10, 20, 9] N = 2 出力 : [40, 20] アルゴリズム 整数のリストと、取得する要素数Nを受け取ります。 N回のループを実行します。 各ループでリスト内の最大値を探し、新しいリストに格納すると同時に元のリストから削除します。 実装コード def Nnumberele(list1, N):