|
| 1 | +class Solution: |
| 2 | + def productExceptSelf(self, nums: list[int]) -> list[int]: |
| 3 | + n = len(nums) |
| 4 | + answer = [1] * n |
| 5 | + |
| 6 | + left = 1 |
| 7 | + for i in range(n): |
| 8 | + answer[i] = left |
| 9 | + left *= nums[i] |
| 10 | + |
| 11 | + right = 1 |
| 12 | + for i in range(n-1, -1, -1): |
| 13 | + answer[i] *= right |
| 14 | + right *= nums[i] |
| 15 | + |
| 16 | + return answer |
| 17 | + |
| 18 | +""" |
| 19 | +================================================================================ |
| 20 | +풀이 과정 - 09:43 시작 ~ 풀이 과정 떠올리지 못함 |
| 21 | +================================================================================ |
| 22 | +
|
| 23 | +1. 정수 배열 nums가 주어짐 |
| 24 | +2. 배열 answer를 반환해야 하는데 |
| 25 | +3. answer[i]는 nums의 모든 요소의 곱과 같다 (nums[i]를 제외한) |
| 26 | +4. O(n) 시간에 실행되는 알고리즘을 작성해야하고, 나누기 연산을 사용해서는 안된다 |
| 27 | +5. 나누기 연산을 어떻게 이용 안하고 풀지? |
| 28 | +
|
| 29 | +──────────────────────────────────────────────────────────────────────────────── |
| 30 | +6. Claude 도움 → answer[i] = (i 왼쪽의 곱) * (i 오른쪽의 곱) |
| 31 | +
|
| 32 | +
|
| 33 | +[1차 시도] 왼쪽/오른쪽 곱 배열 사용 |
| 34 | +──────────────────────────────────────────────────────────────────────────────── |
| 35 | +7. 각 위치의 왼쪽 누적곱과 오른쪽 누적곱을 미리 계산 |
| 36 | +8. left[i] = nums[0] * ... * nums[i-1] |
| 37 | +9. right[i] = nums[i+1] * ... * nums[n-1] |
| 38 | +10. answer[i] = left[i] * right[i] |
| 39 | +
|
| 40 | + n = len(nums) |
| 41 | + left = [1] * n |
| 42 | + for i in range(1, n): |
| 43 | + left[i] = left[i-1] * nums[i-1] |
| 44 | +
|
| 45 | + right = [1] * n |
| 46 | + for i in range(n-2, -1, -1): |
| 47 | + right[i] = right[i+1] * nums[i+1] |
| 48 | +
|
| 49 | + return [left[i] * right[i] for i in range(n)] |
| 50 | +
|
| 51 | +11. 정상적으로 통과되는 것 확인 완료 |
| 52 | +
|
| 53 | +
|
| 54 | +[2차 개선] 공간 복잡도 최적화 |
| 55 | +──────────────────────────────────────────────────────────────────────────────── |
| 56 | +12. left, right 배열을 따로 만들면 O(n) 공간 복잡도 추가 사용 |
| 57 | +13. answer 배열을 재활용하면 추가 공간 없이 해결 가능 |
| 58 | +14. 첫 번째 순회: answer에 왼쪽 누적곱 저장 |
| 59 | +15. 두 번째 순회: answer에 오른쪽 누적곱을 곱하면서 최종 결과 완성 |
| 60 | +
|
| 61 | + n = len(nums) |
| 62 | + answer = [1] * n |
| 63 | +
|
| 64 | + left = 1 |
| 65 | + for i in range(n): |
| 66 | + answer[i] = left |
| 67 | + left *= nums[i] |
| 68 | +
|
| 69 | + right = 1 |
| 70 | + for i in range(n-1, -1, -1): |
| 71 | + answer[i] *= right |
| 72 | + right *= nums[i] |
| 73 | +
|
| 74 | + return answer |
| 75 | +
|
| 76 | +16. 추가 공간 복잡도 O(n) → O(1)로 개선 완료 (answer 배열 제외) |
| 77 | +17. 최종 통과 확인 완료 |
| 78 | +
|
| 79 | +
|
| 80 | +[문제 복기] 패턴 발견 과정 |
| 81 | +──────────────────────────────────────────────────────────────────────────────── |
| 82 | +- 문제를 다시 복기해보면 |
| 83 | +- 각 위치에서 자기 자신을 제외한 모든 원소의 곱을 구해야함 |
| 84 | +- 제약을 무시하면 이중 반복문 Brute Force로 풀 수 있음 |
| 85 | +- 제약을 무시하면 나눗셈을 이용해서도 풀 수 있음 |
| 86 | +- 나눗셈도 금지되고 O(n) 시간에 풀어야한다면? |
| 87 | +- "제외한다"를 어떻게 표현해주면 좋을까? (이 부분이 핵심) |
| 88 | +
|
| 89 | +작은 예시로 패턴 찾기: |
| 90 | + nums = [2, 3, 4] |
| 91 | +
|
| 92 | + answer[0] = 3 * 4 = 12 |
| 93 | + answer[1] = 2 * 4 = 8 |
| 94 | + answer[2] = 2 * 3 = 6 |
| 95 | +
|
| 96 | + answer[0] = (없음) * (3 * 4) = 12 |
| 97 | + answer[1] = (2) * (4) = 8 |
| 98 | + answer[2] = (2 * 3) * (없음) = 6 |
| 99 | +
|
| 100 | +- 패턴 발견 → 왼쪽 부분 * 오른쪽 부분 |
| 101 | +- 해법 도출 → 왼쪽 부분의 모든 곱 * 오른쪽 부분의 모든 곱 |
| 102 | +
|
| 103 | +패턴을 일반화하는 과정이 필요: |
| 104 | + answer[i] = nums[0] * ... * nums[i-1] * nums[i+1] * ... * nums[n-1] |
| 105 | + left[i] = nums[0] * ... * nums[i-1] |
| 106 | + right[i] = nums[i+1] * ... * nums[n-1] |
| 107 | + answer[i] = left[i] * right[i] |
| 108 | +
|
| 109 | +점화식 찾는데, DP적 사고 필요: |
| 110 | + 왼쪽 누적곱: |
| 111 | + left[1] = nums[0] |
| 112 | + left[2] = nums[0] * nums[1] = left[1] * nums[1] |
| 113 | + left[3] = nums[0] * nums[1] * nums[2] = left[2] * nums[2] |
| 114 | + → left[i] = left[i-1] * nums[i-1] |
| 115 | +
|
| 116 | + 오른쪽 누적곱: |
| 117 | + right[2] = nums[3] |
| 118 | + right[1] = nums[3] * nums[2] = right[2] * nums[2] |
| 119 | + right[0] = nums[3] * nums[2] * nums[1] = right[1] * nums[1] |
| 120 | + → right[i] = right[i+1] * nums[i+1] |
| 121 | +
|
| 122 | +관련해서 코드로 구현하는 과정이 필요함 |
| 123 | +""" |
0 commit comments