|
| 1 | +/** |
| 2 | + * 배열에서 합이 0이 되는 세 숫자를 찾기 |
| 3 | + * |
| 4 | + * 요구사항 & 제약조건: |
| 5 | + * 세 개의 다른 인덱스에 있는 숫자들의 합이 0이 되어야 함 |
| 6 | + * 결과에 중복된 조합이 없어야 함 |
| 7 | + * 배열 크기는 3에서 3000까지 |
| 8 | + * 배열 요소는 -10^5부터 10^5까지의 정수 |
| 9 | + * |
| 10 | + * 접근방법: |
| 11 | + * 1. 브루트포스(이중for문, 완전탐색) - O(n^3) 시간복잡도 |
| 12 | + * 2. 정렬 후 투 포인터 - O(n^2) 시간복잡도 ✅ |
| 13 | + * |
| 14 | + * 배열을 정렬 후, 배열을 순회하며 각 요소를 첫 번째 숫자로 고정 |
| 15 | + * 고정된 숫자 다음부터 ~ 배열 끝까지 투 포인터를 사용 ➡️ 나머지 두 수의 합이 첫 번째 수의 음수가 되는 조합 찾기 |
| 16 | + * 중복을 피하기 위해 같은 값을 가진 연속된 요소는 스킵 |
| 17 | + */ |
| 18 | + |
| 19 | +/** |
| 20 | + * @param {number[]} nums |
| 21 | + * @return {number[][]} |
| 22 | + */ |
| 23 | +var threeSum = function (nums) { |
| 24 | + const result = []; |
| 25 | + const n = nums.length; |
| 26 | + |
| 27 | + if (n < 3) return result; |
| 28 | + |
| 29 | + nums.sort((a, b) => a - b); // 오름차순 정렬 |
| 30 | + |
| 31 | + if (nums[0] > 0 || nums[n - 1] < 0) return result; |
| 32 | + |
| 33 | + // 배열을 순회하며 첫 번째 숫자 고정 |
| 34 | + for (let i = 0; i < n - 2; i++) { |
| 35 | + // 중복된 값 건너뛰기 (첫 번째 숫자) |
| 36 | + if (i > 0 && nums[i] === nums[i - 1]) continue; |
| 37 | + |
| 38 | + // 첫 번째 숫자가 양수면 for문 탈출 |
| 39 | + if (nums[i] > 0) break; |
| 40 | + |
| 41 | + // 현재 숫자와 가장 작은 두 숫자의 합 > 0 => 탈출 |
| 42 | + if (nums[i] + nums[i + 1] + nums[i + 2] > 0) break; |
| 43 | + |
| 44 | + // 현재 숫자와 가장 큰 두 숫자의 합 < 0 => 건너뛰기 |
| 45 | + if (nums[i] + nums[n - 2] + nums[n - 1] < 0) continue; |
| 46 | + |
| 47 | + // 두 번째, 세 번째 숫자를 찾기 위한 투 포인터 |
| 48 | + let left = i + 1; |
| 49 | + let right = n - 1; |
| 50 | + |
| 51 | + while (left < right) { |
| 52 | + const sum = nums[i] + nums[left] + nums[right]; |
| 53 | + |
| 54 | + if (sum < 0) { |
| 55 | + // 합이 0보다 작으면 left 포인터를 오른쪽으로 이동 |
| 56 | + left++; |
| 57 | + } else if (sum > 0) { |
| 58 | + // 합이 0보다 크면 right 포인터를 왼쪽으로 이동 |
| 59 | + right--; |
| 60 | + } else { |
| 61 | + // 합이 0이면 결과에 추가 |
| 62 | + result.push([nums[i], nums[left], nums[right]]); |
| 63 | + |
| 64 | + // 중복된 값 건너뛰기 (두 번째, 세 번째 숫자) |
| 65 | + while (left < right && nums[left] === nums[left + 1]) left++; |
| 66 | + while (left < right && nums[right] === nums[right - 1]) right--; |
| 67 | + |
| 68 | + // 다음 조합을 찾기 위해 포인터 이동 |
| 69 | + left++; |
| 70 | + right--; |
| 71 | + } |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + return result; |
| 76 | +}; |
0 commit comments