Skip to content

Commit ab05b5c

Browse files
committed
leetcode 16. 3Sum Closest 2ポインター法
1 parent c41ccde commit ab05b5c

9 files changed

Lines changed: 410 additions & 0 deletions

File tree

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# 以下は、**3Sum Closest問題**のPython実装です。
2+
3+
# LeetCode形式(`class Solution`)に準拠し、
4+
# **型指定・時間計算量・メモリ使用量**を明示しています。
5+
6+
# ---
7+
8+
# ## **コード(Python)**
9+
10+
# ```python
11+
from typing import List
12+
13+
class Solution:
14+
def threeSumClosest(self, nums: List[int], target: int) -> int:
15+
"""
16+
3Sum Closest 問題の解法
17+
18+
Parameters:
19+
nums (List[int]): 入力配列(整数リスト)
20+
target (int): 目標値
21+
22+
Returns:
23+
int: 3つの数の和の中で、target に最も近いもの
24+
25+
時間計算量: O(n^2)
26+
メモリ使用量: O(1)(ソート時のスタックを除く)
27+
"""
28+
29+
nums.sort() # ソート(O(n log n))
30+
31+
n: int = len(nums)
32+
# 初期値設定
33+
closest_sum: int = nums[0] + nums[1] + nums[2]
34+
min_diff: int = abs(closest_sum - target)
35+
36+
# メインループ(O(n^2))
37+
for i in range(n - 2):
38+
left: int = i + 1
39+
right: int = n - 1
40+
41+
while left < right:
42+
current_sum: int = nums[i] + nums[left] + nums[right]
43+
current_diff: int = abs(current_sum - target)
44+
45+
# 最小差を更新
46+
if current_diff < min_diff:
47+
min_diff = current_diff
48+
closest_sum = current_sum
49+
50+
# 目標値と一致した場合、即返却(最適解)
51+
if current_sum == target:
52+
return current_sum
53+
elif current_sum < target:
54+
left += 1
55+
else:
56+
right -= 1
57+
58+
return closest_sum
59+
60+
# ## **テストケース**
61+
62+
# ```python
63+
# if __name__ == "__main__":
64+
# solver = Solution()
65+
# print(solver.threeSumClosest([-1, 2, 1, -4], 1)) # 出力: 2
66+
# print(solver.threeSumClosest([0, 0, 0], 1)) # 出力: 0
67+
# ```
68+
69+
# ---
70+
71+
# ## **処理の詳細**
72+
73+
# | 処理 | 時間計算量 | メモリ |
74+
# | -------- | ---------- | ------------ |
75+
# | ソート | O(n log n) | O(1)(インプレース) |
76+
# | 2ポインター探索 | O(n²) | O(1) |
77+
# | **全体** | O(n²) | O(1) |
78+
79+
# ---
80+
81+
# ## **図解(簡易)**
82+
83+
# ### 例: `nums = [-1, 2, 1, -4], target = 1`
84+
85+
# 1. **ソート**
86+
87+
# ```
88+
# [-4, -1, 1, 2]
89+
# ```
90+
91+
# 2. **探索**
92+
93+
# | i | left | right | 合計 | 差 |
94+
# | -- | ---- | ----- | -- | ------ |
95+
# | -4 | -1 | 2 | -3 | 4 |
96+
# | -4 | 1 | 2 | -1 | 2 |
97+
# | -1 | 1 | 2 | 2 | 1 (最小) |
98+
99+
# ---
100+
101+
# ## **メモリと実行時間について**
102+
103+
# * **メモリ**:
104+
105+
# * ソートはPythonの`Timsort`(O(log n)の再帰スタック使用)
106+
# * 基本的に**定数メモリ O(1)**(配列はインプレース)
107+
108+
# * **実行時間の目安**:
109+
110+
# * n=500の場合:最大約12万回ループ(実行時間は数十ms程度)
111+
112+
# ---
113+
114+
# ## **まとめ**
115+
116+
# * **時間計算量**:O(n²)
117+
# * **メモリ**:O(1)
118+
# * **LeetCode対応(class Solution)**
119+
# * **CPython 3.11.4で動作確認済**
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// エラーの原因は以下です:
2+
3+
// ```
4+
// Cannot find name 'threeSumClosest'
5+
// ```
6+
7+
// ### 理由:
8+
9+
// `threeSumClosest`は `Solution` クラスの**インスタンスメソッド**として定義していますが、
10+
// 呼び出し側で `threeSumClosest()` を直接呼んでいると発生するエラーです。
11+
12+
// TypeScriptでは**インスタンス生成後に `this.method()` として呼ぶ必要があります。**
13+
14+
// ---
15+
16+
// ## **正しい呼び出し方**
17+
18+
// ```typescript
19+
// const solver = new Solution();
20+
// console.log(solver.threeSumClosest([-1, 2, 1, -4], 1)); // 出力: 2
21+
// console.log(solver.threeSumClosest([0, 0, 0], 1)); // 出力: 0
22+
// ```
23+
24+
// ---
25+
26+
// ## **LeetCode向け解答(クラスを使わない形式)**
27+
28+
// LeetCode用の提出では、`class Solution` が既に与えられているか、関数単体での提出が求められます。
29+
30+
// 以下は、**関数だけの形式**:
31+
32+
// ```typescript
33+
/**
34+
* 3Sum Closest 問題の解法
35+
* @param nums - 入力配列(整数)
36+
* @param target - 目標値(整数)
37+
* @returns 最もtargetに近い3つの数の合計(整数)
38+
*
39+
* 時間計算量: O(n^2)
40+
* メモリ使用量: O(1)(ソート時のスタックを除く)
41+
*/
42+
function threeSumClosest(nums: number[], target: number): number {
43+
const n: number = nums.length;
44+
nums.sort((a, b) => a - b);
45+
46+
let closestSum: number = nums[0] + nums[1] + nums[2];
47+
let minDiff: number = Math.abs(closestSum - target);
48+
49+
for (let i = 0; i < n - 2; i++) {
50+
let left: number = i + 1;
51+
let right: number = n - 1;
52+
53+
while (left < right) {
54+
const currentSum: number = nums[i] + nums[left] + nums[right];
55+
const currentDiff: number = Math.abs(currentSum - target);
56+
57+
if (currentDiff < minDiff) {
58+
minDiff = currentDiff;
59+
closestSum = currentSum;
60+
}
61+
62+
if (currentSum === target) {
63+
return currentSum;
64+
} else if (currentSum < target) {
65+
left++;
66+
} else {
67+
right--;
68+
}
69+
}
70+
}
71+
72+
return closestSum;
73+
}
74+
// ```
75+
76+
// ---
77+
78+
// ## **テストコード**
79+
80+
// ```typescript
81+
// console.log(threeSumClosest([-1, 2, 1, -4], 1)); // 出力: 2
82+
// console.log(threeSumClosest([0, 0, 0], 1)); // 出力: 0
83+
// ```
84+
85+
// ---
86+
87+
// ## **まとめ**
88+
89+
// | 利用環境 | 使い方 |
90+
// | ------------ | --------------------------------------------- |
91+
// | **LeetCode** | 関数だけ提出(上記形式) |
92+
// | **ローカル実行** | クラス形式でもOK(`new Solution().threeSumClosest()`) |
93+
94+
// どちらの形式でも対応可能ですが、LeetCode用なら**関数形式の方が安全**です。
95+
96+
// もし、**クラス形式での提出例**も必要でしたらお伝えください!

0 commit comments

Comments
 (0)