Pythonで障害のあるリストから欠落した正しいセンサー値を検出するプログラム
問題の概要
2つのリスト nums1 と nums2 があるとします。これらはそれぞれセンサーが計測した値を表しています。どちらのリストにも重複した値は含まれていません。ところが、片方のリストには正確な計測値が記録されている一方で、もう片方のリストには障害によって不正なデータが混入しています。
障害のあるリストでは、末尾以外の値が1つ削除され、その代わりに誤った値がリストの末尾に追加されています。この記事では、削除されてしまった本来のセンサー値を特定するプログラムを紹介します。
具体例
たとえば、次の入力を考えてみましょう。
- nums1 = [5, 10, 15]
- nums2 = [10, 15, 8]
この場合の出力は 5 となります。nums1 が正しい値 [5, 10, 15] を保持しており、nums2 の側では「5」が削除され、代わりに誤った値「8」が末尾に挿入されているためです。
解き方:二分探索で不一致点を見つける
この問題は二分探索(バイナリサーチ)を使うことで効率よく解決できます。障害のあるリストには重要な特徴があります。それは、「ある位置を境にして、それより前は両リストの要素が一致し、その位置以降は1つずつずれる」というものです。この境界(最初に不一致となる位置)を二分探索で絞り込めば、削除された値を特定できます。
具体的な手順は以下の通りです。
- low を 0、high を「nums1 のサイズ − 1」で初期化します。
- low < high の間、次の処理を繰り返します。
- mid := (low + high) // 2(小数点以下を切り捨て)
- nums1[mid] と nums2[mid] が等しければ → low := mid + 1(不一致点は後半にある)
- 等しくなければ → high := mid(不一致点は mid 以前にある)
- ループ終了後、low は最初の不一致位置を指しています。nums1[low + 1] が nums2[low] と一致すれば nums1 が正しいリストなので nums1[low] を返し、そうでなければ nums2 が正しいので nums2[low] を返します。
最後の判定について補足すると、もし nums2 側で値が1つ抜けているなら、nums2 の要素は nums1 よりも1つ後ろの位置に対応します。つまり nums1[low + 1] == nums2[low] が成り立つとき、正しいのは nums1 ということになり、削除された値は nums1[low] です。逆の場合は nums2 が正しく、答えは nums2[low] となります。
Pythonでの実装例
def solve(nums1, nums2):
low, high = 0, len(nums1) - 1
while low < high:
mid = (low + high) // 2
if nums1[mid] == nums2[mid]:
low = mid + 1
else:
high = mid
return nums1[low] if nums1[low + 1] == nums2[low] else nums2[low]
nums1 = [5, 10, 15]
nums2 = [10, 15, 8]
print(solve(nums1, nums2))
入力
[5, 10, 15], [10, 15, 8]
出力
5
処理の流れを追ってみる
上記の例では、次のように探索が進みます。
- 初期状態:low = 0、high = 2
- 1回目:mid = 1。nums1[1] = 10 と nums2[1] = 15 は一致しないため、high = 1 に更新
- 2回目:mid = 0。nums1[0] = 5 と nums2[0] = 10 も一致しないため、high = 0 に更新
- low = high = 0 となりループ終了。最初の不一致位置はインデックス 0
- nums1[1] = 10 と nums2[0] = 10 が一致するため、nums2 の方が1つずれている(= nums2 が障害側)。よって nums1[0] = 5 を返す
計算量
このアルゴリズムの時間計算量は O(log n) です。リスト全体を先頭から順に比較する線形探索(O(n))に比べ、データサイズが大きくなるほど圧倒的に高速に動作します。また、空間計算量は O(1) で、追加のメモリもほとんど必要ありません。センサーデータのような大量の時系列データを扱う場合に、この手法は特に有効です。
-
Pythonで木の辺を1本取り除いたときの部分木のノード値合計の差の最小値を求めるプログラム
問題の概要ノードに1からnまでの番号が振られた木があるとします。各ノードには整数値が格納されています。ここで、木からある1本の辺を取り除くと、木は2つの部分木に分割されます。このとき、2つの部分木のノード値の合計の差が最小になるようにしたいと考えます。私たちのタスクは、その最小の差を求めて返すことです。木は辺のリストとして与えられ、各ノードの値も併せて提供されます。例として、n = 6、edge_list = [[1, 2], [1, 3], [2, 4], [3, 5], [3, 6]]、values = [15, 25, 15, 55, 15, 65] が入力された場合、出力は 0 になり
-
Pythonでリスト内の最小値を見つける方法を解説
この記事では、リストの中から最小の数値を見つける方法について、具体的なサンプルコードとともに詳しく解説します。問題の概要問題: 数値のリストが与えられたとき、その中に含まれる最も小さい数値を画面に表示すること。この問題を解くアプローチは主に2つあります。ひとつは sort() メソッドを使ってリストを昇順に並べ替え、先頭の要素(インデックス0)を取得する方法。もうひとつは、Pythonに標準で用意されている組み込み関数 min() を使う方法です。それぞれ順番に見ていきましょう。方法1:sort()メソッドで並べ替えて最小値を取得するまずはリストを昇順にソートし、先頭の要素を取り出す方法です。