1+ class Solution :
2+ def threeSum (self , nums : list [int ]) -> list [list [int ]]:
3+ nums .sort ()
4+ result = set ()
5+
6+ for i in range (len (nums ) - 2 ):
7+ # 양수인 경우 더 이상 탐색할 필요가 없음
8+ if nums [i ] > 0 :
9+ break
10+
11+ # i 중복 skip
12+ if i > 0 and nums [i ] == nums [i - 1 ]:
13+ continue
14+
15+ left = i + 1
16+ right = len (nums ) - 1
17+
18+ while left < right :
19+ total = nums [i ] + nums [left ] + nums [right ]
20+
21+ if total == 0 :
22+ result .add ((nums [i ], nums [left ], nums [right ]))
23+
24+ # 중복 건너뛰기
25+ while left < right and nums [left ] == nums [left + 1 ]:
26+ left += 1
27+ # 중복 건너뛰기
28+ while left < right and nums [right ] == nums [right - 1 ]:
29+ right -= 1
30+ left += 1
31+ right -= 1
32+ elif total < 0 :
33+ left += 1
34+ else :
35+ right -= 1
36+
37+ return [list (t ) for t in result ]
38+
39+
40+ """
41+ ================================================================================
42+ 풀이 과정 - 10:51 시작
43+ ================================================================================
44+
45+ 1. 정수 배열 nums가 주어지면
46+ 2. 모든 세 쌍 [nums[i], nums[j], nums[k]]을 반환해야한다
47+ 3. i != j, i != k, j != k 여야하고
48+ 4. nums[i] + nums[j] + nums[k] == 0 이어야한다
49+ 5. 중복된 세 쌍이 포함되지 않아야한다
50+
51+
52+ [1차 시도] Brute Force 3중 반복문
53+ ────────────────────────────────────────────────────────────────────────────────
54+ 6. 제약을 무시하고 생각해보면 Brute Force 3중 반복문으로 찾을 수 있을 것 같음
55+ 7. 중복도 제거해야하니까 마지막에 set을 두고 처리
56+
57+ result = []
58+ n = len(nums)
59+
60+ for i in range(n):
61+ for j in range(i+1, n):
62+ for k in range(j+1, n):
63+ if nums[i] + nums[j] + nums[k] == 0:
64+ triplet = sorted([nums[i], nums[j], nums[k]])
65+ if triplet not in result:
66+ result.append(triplet)
67+
68+ return result
69+
70+ 8. Time Limit Exceeded 발생
71+ 9. O(n³) 시간 복잡도로 너무 느림
72+
73+
74+ [2차 시도] Two Sum 응용 (HashSet)
75+ ────────────────────────────────────────────────────────────────────────────────
76+ 10. 3개를 동시에 찾으려니까 어려운 것 같은데
77+ 11. 2개를 먼저 구하고, 나머지 하나를 더하면 0이 되는지를 확인해볼까
78+ 12. 두 수의 합 = 나머지 하나의 값
79+ 13. -nums[i] = nums[j] + nums[k]
80+ 14. 그럼 Two Sum 문제로 풀 수 있을듯?
81+ 15. 두 개의 합이 set에 존재하는지를 체크하는 형태로 가보자
82+
83+ result = set()
84+
85+ for i in range(len(nums)):
86+ seen = set()
87+ for j in range(i + 1, len(nums)):
88+ complement = -(nums[i] + nums[j])
89+ if complement in seen:
90+ result.add(tuple(sorted([nums[i], nums[j], complement])))
91+ seen.add(nums[j])
92+
93+ return [list(x) for x in result]
94+
95+ 16. 아 근데 이것도 Time Limit Exceeded가 발생하네
96+ 17. O(n²) 시간 복잡도로 개선했지만 sorted() 호출과 set 연산이 추가 비용 발생
97+ 18. 다른 접근 방법이 필요할 듯
98+
99+
100+ [3차 시도] Two Pointer 방식
101+ ────────────────────────────────────────────────────────────────────────────────
102+ 19. 그럼 Two Pointer 방식으로 풀어야할 것 같은데
103+ 20. Two Pointer 방식을 사용하려면 정렬이 필요함
104+ 21. Two Sum의 Two Pointer 패턴을 생각해보자
105+ 22. 근데 3개를 동시에 찾으려면 어떻게 해야할까?
106+ 23. i를 고정하고, 나머지에서 Two Sum으로 합이 -nums[i]인 두 수를 찾는다!
107+
108+ 정렬 전: [-1, 0, 1, 2, -1, -4]
109+ 정렬 후: [-4, -1, -1, 0, 1, 2]
110+ index: 0 1 2 3 4 5
111+
112+ i = 0, left = i + 1, right = len(nums) - 1
113+ [-4, -1, -1, 0, 1, 2]
114+ i L R
115+
116+ i = 1:
117+ [-4, -1, -1, 0, 1, 2]
118+ i L R
119+
120+ 25. 정렬 먼저 한 후 합의 크기에 따라 포인터를 이동
121+
122+ nums.sort()
123+ result = set()
124+
125+ for i in range(len(nums) - 2):
126+ left = i + 1
127+ right = len(nums) - 1
128+
129+ while left < right:
130+ total = nums[i] + nums[left] + nums[right]
131+
132+ if total == 0:
133+ result.add((nums[i], nums[left], nums[right]))
134+ left += 1
135+ right -= 1
136+ elif total < 0:
137+ left += 1
138+ else:
139+ right -= 1
140+
141+ return [list(t) for t in result]
142+
143+ 25. O(n²) 시간 복잡도 (정렬 O(n log n) + 반복문 O(n²))
144+ 26. 정상적으로 통과되는 것 확인 완료
145+ 27. 근데 이 방식으로 풀었는데 느리다
146+
147+
148+ [4차 개선] 중복 제거 최적화
149+ ────────────────────────────────────────────────────────────────────────────────
150+ 28. Claude에게 물어보니 tuple 생성할 때 상수 배수가 큰 것 같다고 함
151+ 29. 중복을 미리 스킵해주는 방법을 알려줌
152+ 30. i가 양수인 경우 더 이상 탐색할 필요 없음 (정렬되어 있으므로)
153+ 31. i, left, right 중복 건너뛰기 추가
154+
155+ nums.sort()
156+ result = set()
157+
158+ for i in range(len(nums) - 2):
159+ # 양수인 경우 더 이상 탐색할 필요가 없음
160+ if nums[i] > 0:
161+ break
162+
163+ # i 중복 skip
164+ if i > 0 and nums[i] == nums[i - 1]:
165+ continue
166+
167+ left = i + 1
168+ right = len(nums) - 1
169+
170+ while left < right:
171+ total = nums[i] + nums[left] + nums[right]
172+
173+ if total == 0:
174+ result.add((nums[i], nums[left], nums[right]))
175+
176+ # 중복 건너뛰기
177+ while left < right and nums[left] == nums[left + 1]:
178+ left += 1
179+ while left < right and nums[right] == nums[right - 1]:
180+ right -= 1
181+ left += 1
182+ right -= 1
183+ elif total < 0:
184+ left += 1
185+ else:
186+ right -= 1
187+
188+ return [list(t) for t in result]
189+
190+ 32. 중복 처리 최적화로 속도 개선
191+ 33. 최종 통과 확인 완료
192+ """
0 commit comments