Pythonで3要素の合計がターゲット未満となるトリプレットの個数を数えるプログラム
問題の概要
数値のリスト nums と値 target が与えられたとき、nums[i] + nums[j] + nums[k] < target を満たすトリプレット(i < j < k)の個数を求めることを考えます。
例えば、入力が nums = [-2, 6, 4, 3, 8]、target = 12 の場合、出力は 5 になります。条件を満たすトリプレットは以下の通りです。
- [-2, 6, 4]
- [-2, 6, 3]
- [-2, 4, 3]
- [-2, 4, 8]
- [-2, 3, 8]
解法のアプローチ
すべての組み合わせを総当たりで調べると O(n³) の計算量が必要になりますが、ソート」と「2ポインタ(two-pointer)技法」を組み合わせることで、O(n²) まで計算量を抑えられます。
解くための手順は以下の通りです。
- リスト
numsを昇順にソートする ans := 0と初期化するn := numsのサイズとするiを 0 から n−1 までループするk := n − 1とするjを i+1 から n−1 までループするk > jかつnums[i] + nums[k] + nums[j] >= targetの間、kを 1 減らし続けるj == kになったらループを抜けるans += k − jを加算する
ansを返す
このアルゴリズムのポイントは、リストがソート済みであるため、j と k の間に含まれるすべての要素 m について nums[i] + nums[j] + nums[m] < target が自動的に成り立つという点です。つまり、条件を満たす範囲の幅(k − j)を一度に数え上げることができ、個別の組み合わせをすべて列挙する必要がありません。
実装例
以下にPythonでの実装例を示します。
class Solution: def solve(self, nums, target): nums.sort() ans = 0 n = len(nums) for i in range(n): k = n - 1 for j in range(i + 1, n): while k > j and nums[i] + nums[k] + nums[j] >= target: k -= 1 if j == k: break ans += k - j return ans ob1 = Solution() nums = [-2, 6, 4, 3, 8] target = 12 print(ob1.solve(nums, target))
入力
[-2, 6, 4, 3, 8], 12
出力
5
まとめ
このように、ソートと2ポインタ技法を活用することで、3重ループによる総当たりよりも大幅に効率的に、合計がターゲット未満となるトリプレットの個数を求めることができます。同様の手法は「3Sum」系の問題全般に応用できるため、ぜひ覚えておきましょう。
-
Pythonで二分木の合計がkとなるパスの数を数える方法
問題の概要 二分木と値 k が与えられたとき、あるノードからその子孫へ向かうパスのうち、通過するノードの値の合計がちょうど k と一致するものがいくつ存在するかを求める問題です。 例えば、次のような二分木を考えてみましょう。 このとき k = 5 であれば、出力は 2 となります。条件を満たすパスは [2, 3] と [1, 4] の2つだからです。 解き方のアプローチ:累積和(prefix sum)の活用 この問題は「累積和(prefix sum)」というテクニックを使うことで、全ノードを一度だけ訪問する効率的なアルゴリズムとして解けます。考え方の手順は以下の通りです。 count:マッ
-
【Python入門】数値が素数かどうかを判定するプログラムの書き方
この記事では、ユーザーが入力した数値(1より大きい整数)が素数かどうかを判定するPythonプログラムを紹介します。サンプルコードと実行結果、処理の流れを丁寧に解説しているので、Python初心者の方でも理解しやすい内容になっています。素数とは?素数とは、1より大きい正の整数のうち、約数が1とその数自身の2つしか存在しない数のことです。たとえば、2・3・5・7・11などは約数が1と自分自身だけであるため素数です。一方、4や6のように1と自分自身以外の約数を持つ数は「合成数」と呼ばれます。素数判定プログラムのサンプルコード# 入力された数値が素数かどうかを判定するPythonプログラム # ユ