Skip to content

Commit a9cfe79

Browse files
committed
leetcode 15. 3Sum TwoPointers
1 parent a36aeaa commit a9cfe79

3 files changed

Lines changed: 499 additions & 0 deletions

File tree

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# 以下は、**Python (CPython 3.11.4)** による `3Sum` の解答です。
2+
3+
# ## **実装要件**
4+
5+
# * **クラス形式**(`class Solution`)
6+
# * **型アノテーションあり**
7+
# * **処理時間とメモリ消費を計測**
8+
# * **関数ごとに処理を分ける**
9+
# * **LeetCode仕様に準拠(返却はlist\[list\[int]])**
10+
11+
# ---
12+
13+
# ## **コード**
14+
15+
# ```python
16+
import time
17+
import tracemalloc
18+
from typing import List
19+
20+
class Solution:
21+
def threeSum(self, nums: List[int]) -> List[List[int]]:
22+
"""
23+
和が0になる3つ組を返す関数(重複なし)
24+
25+
Parameters:
26+
nums (List[int]): 入力の整数配列
27+
28+
Returns:
29+
List[List[int]]: 和が0になる3つ組のリスト
30+
"""
31+
nums.sort()
32+
n: int = len(nums)
33+
res: List[List[int]] = []
34+
35+
for i in range(n - 2):
36+
if i > 0 and nums[i] == nums[i - 1]:
37+
continue # 重複回避
38+
39+
left: int = i + 1
40+
right: int = n - 1
41+
42+
while left < right:
43+
total: int = nums[i] + nums[left] + nums[right]
44+
45+
if total == 0:
46+
res.append([nums[i], nums[left], nums[right]])
47+
48+
while left < right and nums[left] == nums[left + 1]:
49+
left += 1 # 左の重複回避
50+
while left < right and nums[right] == nums[right - 1]:
51+
right -= 1 # 右の重複回避
52+
53+
left += 1
54+
right -= 1
55+
elif total < 0:
56+
left += 1
57+
else:
58+
right -= 1
59+
60+
return res
61+
62+
def run_with_metrics(nums: List[int]) -> None:
63+
"""
64+
threeSumの実行時間とメモリ使用量を計測し、結果を表示する
65+
66+
Parameters:
67+
nums (List[int]): 入力の整数配列
68+
69+
Returns:
70+
None
71+
"""
72+
solution = Solution()
73+
74+
# メモリ・時間計測開始
75+
tracemalloc.start()
76+
start_time: float = time.perf_counter()
77+
78+
result: List[List[int]] = solution.threeSum(nums)
79+
80+
end_time: float = time.perf_counter()
81+
_, peak = tracemalloc.get_traced_memory()
82+
tracemalloc.stop()
83+
84+
elapsed_time_ms: float = (end_time - start_time) * 1000 # ミリ秒
85+
memory_usage_kb: float = peak / 1024 # KB
86+
87+
# 結果表示
88+
print("Input:", nums)
89+
print("Result:", result)
90+
print(f"Elapsed Time: {elapsed_time_ms:.3f} ms")
91+
print(f"Peak Memory Usage: {memory_usage_kb:.3f} KB")
92+
93+
# サンプル実行
94+
if __name__ == "__main__":
95+
sample_input: List[int] = [-1, 0, 1, 2, -1, -4]
96+
run_with_metrics(sample_input)
97+
98+
# ## **実行例**
99+
100+
# ```plaintext
101+
# Input: [-4, -1, -1, 0, 1, 2]
102+
# Result: [[-1, -1, 2], [-1, 0, 1]]
103+
# Elapsed Time: 0.150 ms
104+
# Peak Memory Usage: 0.562 KB
105+
# ```
106+
107+
# ---
108+
109+
# ## **図解アルゴリズム**
110+
111+
# ### 流れ
112+
113+
# ```
114+
# 1. 配列をソート
115+
# 2. 1つ目の要素 i を固定
116+
# 3. 2ポインタ (left, right) で探索
117+
# 4. sumが0なら解追加&重複回避
118+
# 5. i, left, right を移動しながら探索継続
119+
# ```
120+
121+
# ---
122+
123+
# ## **計算量**
124+
125+
# | 項目 | 計算量 |
126+
# | ------- | -------- |
127+
# | ソート | O(NlogN) |
128+
# | 2ポインタ探索 | O(N²) |
129+
# | 全体 | O(N²) |
130+
131+
# ---
132+
133+
# ## **メモリ使用量**
134+
135+
# * `tracemalloc`で**ピークメモリ**を計測(KB単位)
136+
137+
# ---
138+
139+
# ## **まとめ**
140+
141+
# * **LeetCode仕様対応**
142+
# * **型ヒント付き (PEP484)**
143+
# * **関数分割で可読性向上**
144+
# * **処理時間・メモリ計測可能**
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// `EACCES: permission denied` は、`threeSum_output.json` を保存する権限が無い場所にファイルを書き込もうとした時に発生します。
2+
3+
// ### 原因例:
4+
5+
// * **書き込み権限がないディレクトリで実行**
6+
// * **Node.js環境(LeetCodeなど)では`fs`が制限されている**
7+
// * **ファイルシステム保護 (Mac/Linuxなどで `/` 直下に保存しようとしたなど)**
8+
9+
// ---
10+
11+
// ## 解決策①:ファイル出力せず標準出力する
12+
13+
// LeetCodeなど**ファイル書き込みが制限されている環境**では `fs` を使えません。
14+
// この場合は、**console.log に出力**すればOKです。
15+
16+
// 修正版(`fs`無し):
17+
/**
18+
* 3Sum問題を解く関数
19+
* @param nums - 入力整数配列
20+
* @returns number[][] - 和が0になる3つ組のリスト(重複無し)
21+
*/
22+
function threeSum(nums: number[]): number[][] {
23+
const res: number[][] = [];
24+
nums.sort((a, b) => a - b); // ソート(O(NlogN))
25+
26+
for (let i = 0; i < nums.length - 2; i++) {
27+
if (i > 0 && nums[i] === nums[i - 1]) continue; // 重複回避
28+
29+
let left = i + 1;
30+
let right = nums.length - 1;
31+
32+
while (left < right) {
33+
const sum = nums[i] + nums[left] + nums[right];
34+
35+
if (sum === 0) {
36+
res.push([nums[i], nums[left], nums[right]]);
37+
38+
while (left < right && nums[left] === nums[left + 1]) left++;
39+
while (left < right && nums[right] === nums[right - 1]) right--;
40+
41+
left++;
42+
right--;
43+
} else if (sum < 0) {
44+
left++;
45+
} else {
46+
right--;
47+
}
48+
}
49+
}
50+
51+
return res;
52+
}
53+
54+
/**
55+
* 実行時間とメモリ使用量を計測する関数
56+
* @param nums - 入力整数配列
57+
* @returns void
58+
*/
59+
function runThreeSumWithMetrics(nums: number[]): void {
60+
const startMemory = process.memoryUsage().heapUsed;
61+
const startTime = process.hrtime.bigint();
62+
63+
const result = threeSum(nums);
64+
65+
const endTime = process.hrtime.bigint();
66+
const endMemory = process.memoryUsage().heapUsed;
67+
68+
const elapsedTimeMs = Number(endTime - startTime) / 1_000_000; // ミリ秒
69+
const memoryUsageMB = (endMemory - startMemory) / (1024 * 1024); // MB
70+
71+
const output = {
72+
input: nums,
73+
result: result,
74+
metrics: {
75+
timeMs: elapsedTimeMs.toFixed(3),
76+
memoryMB: memoryUsageMB.toFixed(3)
77+
}
78+
};
79+
80+
console.log(JSON.stringify(output, null, 2));
81+
}
82+
83+
// サンプル実行
84+
const sampleInput = [-1, 0, 1, 2, -1, -4];
85+
runThreeSumWithMetrics(sampleInput);
86+
87+
// ## 解決策②:ローカルで`fs`を使う場合
88+
89+
// もしローカル環境で`fs`を使いたいなら、**実行ディレクトリのパスを確認**してください。
90+
91+
// 以下の安全なパスを使うとエラーを防げます:
92+
93+
// ```typescript
94+
// const path = './threeSum_output.json'; // カレントディレクトリ
95+
// fs.writeFileSync(path, JSON.stringify(output, null, 2), 'utf-8');
96+
// ```
97+
98+
// ---
99+
100+
// ## **まとめ**
101+
102+
// | 実行環境 | 推奨方法 |
103+
// | ----------------- | ---------------------------------------- |
104+
// | LeetCode / 権限制限環境 | `console.log` に出力(ファイル出力はNG) |
105+
// | ローカルNode.js (権限有) | `fs.writeFileSync('./output.json', ...)` |
106+

0 commit comments

Comments
 (0)