-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: solve pg-200-66~67 and add solution 67-explanation
- Loading branch information
Showing
2 changed files
with
103 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# 연속된 부분 수열의 합 | ||
|
||
> 전형적인 투포인터 문제! | ||
전형적인 투포인터 문제이기 때문에 가뿐히(?)까지는 아니지만 적정 시간 안에 풀이한 것 같다. 하지만 여기서 생각해야할 부분은 바로 이것이였다. | ||
|
||
``` | ||
- 합이 k인 부분 수열이 여러 개인 경우 길이가 짧은 수열을 찾습니다. | ||
- 길이가 짧은 수열이 여러 개인 경우 앞쪽(시작 인덱스가 작은)에 나오는 수열을 찾습니다. | ||
``` | ||
|
||
이런 요구 조건으로 인해 좀 더 구현이 필요했다. | ||
|
||
## 코드 | ||
|
||
```js | ||
function solution(sequence, k) { | ||
const result = []; | ||
let p1 = 0, | ||
p2 = 0; | ||
let total = sequence[0]; | ||
|
||
while (p1 <= p2 && p1 < sequence.length && p2 < sequence.length) { | ||
if (total < k) { | ||
p2++; | ||
total += sequence[p2]; | ||
} else if (total > k) { | ||
total -= sequence[p1]; | ||
p1++; | ||
} else { | ||
result.push([p1, p2]); | ||
p2++; | ||
total += sequence[p2]; | ||
} | ||
} | ||
|
||
if (result.length === 1) return result[0]; | ||
|
||
let min = Number.MAX_SAFE_INTEGER; | ||
let answer = []; | ||
for (let i = 0; i < result.length; i++) { | ||
const tmp = result[i][1] - result[i][0]; | ||
if (tmp < min) { | ||
min = tmp; | ||
answer = result[i]; | ||
} | ||
} | ||
return answer; | ||
} | ||
``` | ||
|
||
내가 짠 코드는 이렇다. 뭔가 길어보이지만 단위별로 해야할 기능(?)들이 구분되어 있다. | ||
|
||
- while : 합이 k인 연속된 수열을 찾는다. | ||
- 그 이후 : 찾은 결과값 중에서 가장 짧은 수열을 찾는다. | ||
|
||
이런 식으로 나름 기능 단위로 구분되어 있긴한데... 가독성이 떨어지긴했다. 그리고 쓸데없이 긴 느낌이긴하다. 다른 분들의 코드를 보니, while문 안에서 else 부분, 즉 `k === total` 경우에 이전 값을 가지고 비교하여 짧은 수열을 찾도록 구현되어 있었다. 이게 좀 더 가독성과 이해의 측면에서 나은 부분이라는 생각에 동의하여 한번 리팩토링을 해보았다. | ||
|
||
```js | ||
function solution(sequence, k) { | ||
let p1 = 0, | ||
p2 = 0; | ||
let total = sequence[0]; | ||
let result = [0, sequence.length - 1]; // 1) | ||
|
||
while (p1 <= p2 && p1 < sequence.length && p2 < sequence.length) { | ||
if (total < k) { | ||
p2++; | ||
total += sequence[p2]; | ||
} else if (total > k) { | ||
total -= sequence[p1]; | ||
p1++; | ||
} else { | ||
const prevMin = result[1] - result[0]; | ||
const min = p2 - p1; | ||
if (prevMin > min) result = [p1, p2]; | ||
|
||
p2++; | ||
total += sequence[p2]; | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
``` | ||
|
||
> 리팩토링 코드 | ||
최초 리팩토링 했을때의 몇가지 문제점에 대해서 기록해둔다. | ||
|
||
최초 리팩토링한 코드는 `prevMin` 이라는 변수를 통해서 연속하는 수열의 길이는 담고 있었다. 그런데 굳이 담을 필요가 없겠다는걸 알게 되었다. result에 인덱스값이 결국 연속된 수열의 길이이기 때문이다. | ||
|
||
또 한가지, else 블럭에서 prevMin의 값을 처음엔 아래처럼 처리했다. | ||
|
||
```js | ||
const prevMin = result[1] - result[0] || Number.MAX_SAFE_INTEGER; | ||
``` | ||
|
||
처음엔, result의 초기값이 빈배열이기때문에, prevMin의 초기값 역시 NaN이 되어서 이를 해결하기 위해서 `Number.MAX_SAFE_INTEGER`를 이용해서 최대값을 주었다. 그런데 이 역시 문제가 생겼다. `result[1] - result[0]`이 0인 경우는 의도하지 않게 다시 초기값으로 변경된다. 또 다시 이를 해결하기 위한 방법으로 result의 초기값을 `주어진 배열에서 연속된 수 중에서 나올 수 있는 최대값`을 주는 방법으로 해결하였다. (1번 부분 / 다른분 코드 참고) (혹은 0인 경우를 조건 분기로 처리할 수도 있었겠지만, 굳이 그렇게 까지 해야할 부분은 아니라고 생각했다.) | ||
|
||
리팩토링까지 끝!!🤡 |