Skip to content

Commit

Permalink
feat: solve pg-200-66~67 and add solution 67-explanation
Browse files Browse the repository at this point in the history
  • Loading branch information
jjanmo committed Aug 11, 2023
1 parent 7dd0850 commit 757ba90
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/programmers200.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,5 @@
| 63 | 23.08.08 | - | [가장 먼 노드](https://school.programmers.co.kr/learn/courses/30/lessons/49189) | Done | | |
| 64 | 23.08.08 | | [순위](https://school.programmers.co.kr/learn/courses/30/lessons/49191) | Done | [✔️](/pg200/64.md) | |
| 65 | 23.08.10 | | [신고 결과 받기](https://school.programmers.co.kr/learn/courses/30/lessons/92334) | Done | [✔️](/pg200/65.md) | |
| 66 | 23.08.11 | | [공원 산책](https://school.programmers.co.kr/learn/courses/30/lessons/172928) | Done | | |
| 67 | 23.08.11 | | [연속된 부분 수열의 합](https://school.programmers.co.kr/learn/courses/30/lessons/178870) | Done | [✔️](/pg200/67.md) | |
101 changes: 101 additions & 0 deletions pg200/67.md
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인 경우를 조건 분기로 처리할 수도 있었겠지만, 굳이 그렇게 까지 해야할 부분은 아니라고 생각했다.)

리팩토링까지 끝!!🤡

0 comments on commit 757ba90

Please sign in to comment.