|
| 1 | +"""TC: O(l * i + n), SC: O(n) |
| 2 | +
|
| 3 | +※ 쉬운 길을 돌아가는 풀이라는 것을 감안하고 읽어야 한다!!! |
| 4 | +※ 구간의 끝 값이 10^4라고 되어있는 것을 보고 효율 안 따지고 냅다 아래의 방법으로 접근해보았다. |
| 5 | +
|
| 6 | +n은 전체 구간의 끝 값. 문제에서는 10^4으로 주어져 있다. (구체적으로는, 구간의 시작과 끝이 [0, 10^4] 구간에 존재) |
| 7 | +i는 전체 인터벌의 개수. 문제에서는 10^4으로 주어져 있다. |
| 8 | +l은 각 인터벌의 크기. 문제에서는 10^4으로 주어져 있다. |
| 9 | +
|
| 10 | +아이디어: |
| 11 | +- n칸 짜리 일직선으로 되어있는 벽이 있다고 하자. 이 벽에는 아무런 칠이 되어있지 않다. |
| 12 | + - [0, 0, ..., 0] 리스트라고 생각하자. |
| 13 | +- 모든 인터벌을 순회하면서 인터벌의 시작, 끝 값을 활용하여 이 벽의 일정 구간에 페인트를 칠한다고 하자. |
| 14 | + - 특정 구간의 값을 1로 바꾼다. |
| 15 | + - [0, ..., 0, 1, ..., 1, 0, ..., 0] |
| 16 | + ^ ^ |
| 17 | + s e - 1 |
| 18 | +- 페인트 칠이 끝났으면 벽의 시작부터 끝까지 훑으면서 칠해진 구간을 찾아내어 결과로 리턴한다. |
| 19 | +
|
| 20 | +SC: |
| 21 | +- 벽을 길이 n짜리 리스트로 관리. O(n). |
| 22 | +- 페인트 칠이 완료된 벽에서 구간을 찾을때 구간의 시작, 끝 인덱스를 관리하는 값에서 O(1). |
| 23 | +- 종합하면 O(n). |
| 24 | +
|
| 25 | +TC: |
| 26 | +- 각 인터벌을 순회할 때마다 벽 리스트에서 최대 l개의 아이템에 접근해서 값을 1로 바꾼다. O(l). |
| 27 | +- 위의 작업을 인터벌 개수 만큼 진행. 여기까지 O(l * i). |
| 28 | +- 페인트 칠이 끝난 벽을 순회하며 인터벌 추출. O(n). |
| 29 | +- 종합하면 O(l * i + n). |
| 30 | +""" |
| 31 | + |
| 32 | + |
| 33 | +class Solution: |
| 34 | + def merge(self, intervals: List[List[int]]) -> List[List[int]]: |
| 35 | + max_v = int(1e4 + 2) |
| 36 | + flags = [False] * max_v |
| 37 | + |
| 38 | + for i in intervals: |
| 39 | + for v in range(i[0], i[1] + 1): |
| 40 | + flags[v] = True |
| 41 | + |
| 42 | + res = [] |
| 43 | + |
| 44 | + make_interval = False |
| 45 | + int_s, int_e = -1, -1 |
| 46 | + |
| 47 | + for i in range(max_v): |
| 48 | + if flags[i]: |
| 49 | + # 인터벌에 포함되어야 하는 값 |
| 50 | + if not make_interval: |
| 51 | + # 인터벌의 시작 값이다. 인터벌 시작을 i로 세팅. |
| 52 | + make_interval = True |
| 53 | + int_s = i |
| 54 | + else: |
| 55 | + # 인터벌에 포함된 값이다. 인터벌 끝을 i로 세팅. |
| 56 | + int_e = i |
| 57 | + else: |
| 58 | + # 인터벌에 포함 안되는 값 |
| 59 | + if make_interval: |
| 60 | + # 직전 값까지는 인터벌에 포함되었으므로, i에서 |
| 61 | + # 인터벌이 끝났다. 인터벌을 더해줌. |
| 62 | + res.append([int_s, int_e]) |
| 63 | + make_interval = False |
| 64 | + |
| 65 | + return res |
| 66 | + |
| 67 | + |
| 68 | +""" |
| 69 | +그런데 위의 코드를 제출하면 오답이라고 나온다. 왜냐하면, 문제 조건상 인터벌의 s와 e값이 같을 수 있고, |
| 70 | +따라서 길이 0짜리 구간이 존재할 수 있기 때문!!!!! (길이 0짜리 인터벌이라니... 분노를 금할 수 없다.) |
| 71 | +그래서 위에서 벽에 페인트를 칠하는 비유로는 설명이 불가능한 이상한 인터벌도 결과에 포함시켜서 리턴해야 한다. |
| 72 | +이를 위해서 별도의 처리를 한 것이 아래의 코드다. 추가된 코드를 보기 편하게 하기 위해 한글 변수명을 활용했다. |
| 73 | +""" |
| 74 | + |
| 75 | + |
| 76 | +class Solution: |
| 77 | + def merge(self, intervals: List[List[int]]) -> List[List[int]]: |
| 78 | + max_v = int(1e4 + 2) |
| 79 | + flags = [False] * max_v |
| 80 | + 억까 = [] |
| 81 | + |
| 82 | + for i in intervals: |
| 83 | + for v in range(i[0], i[1]): |
| 84 | + flags[v] = True |
| 85 | + if i[0] == i[1]: |
| 86 | + 억까.append(i[0]) |
| 87 | + |
| 88 | + 억까 = list(set(억까)) |
| 89 | + 억까.sort() |
| 90 | + |
| 91 | + res = [] |
| 92 | + |
| 93 | + make_interval = False |
| 94 | + int_s, int_e = -2, -2 |
| 95 | + 억까_ind = 0 |
| 96 | + |
| 97 | + for i in range(max_v): |
| 98 | + if flags[i]: |
| 99 | + # 인터벌에 포함되어야 하는 값 |
| 100 | + if not make_interval: |
| 101 | + # 길이가 있는 인터벌 앞에 오는 길이 0짜리 인터벌들을 추가해주자. |
| 102 | + while 억까_ind < len(억까) and (v := 억까[억까_ind]) <= i: |
| 103 | + if int_e + 1 < v: |
| 104 | + # 직전에 결과에 추가한 인터벌의 끝 값보다는 커야 한다. |
| 105 | + if v < i: |
| 106 | + res.append([v, v]) |
| 107 | + 억까_ind += 1 |
| 108 | + |
| 109 | + # 인터벌의 시작 값이다. 인터벌의 시작과 끝을 i로 세팅. |
| 110 | + make_interval = True |
| 111 | + int_s = int_e = i |
| 112 | + |
| 113 | + else: |
| 114 | + # 인터벌에 포함된 값이다. 인터벌 끝을 i로 세팅. |
| 115 | + int_e = i |
| 116 | + else: |
| 117 | + # 인터벌에 포함 안되는 값 |
| 118 | + if make_interval: |
| 119 | + # 직전 값까지는 인터벌에 포함되었으므로, i에서 |
| 120 | + # 인터벌이 끝났다. 인터벌을 더해줌. |
| 121 | + res.append([int_s, int_e + 1]) |
| 122 | + make_interval = False |
| 123 | + |
| 124 | + while 억까_ind < len(억까): |
| 125 | + # 끝에 오는 길이 0짜리 인터벌들을 마저 추가해주자. |
| 126 | + if int_e + 1 < (v := 억까[억까_ind]): |
| 127 | + res.append([v, v]) |
| 128 | + 억까_ind += 1 |
| 129 | + |
| 130 | + return res |
0 commit comments