Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[선재] WEEK06 문제 풀이 #476

Merged
merged 4 commits into from
Sep 21, 2024
Merged

[선재] WEEK06 문제 풀이 #476

merged 4 commits into from
Sep 21, 2024

Conversation

Sunjae95
Copy link
Contributor

@Sunjae95 Sunjae95 commented Sep 20, 2024

답안 제출 문제

체크 리스트

  • PR을 프로젝트에 추가하고 Week를 현재 주차로 설정해주세요.
  • 바로 앞에 PR을 열어주신 분을 코드 검토자로 지정해주세요.
  • 문제를 모두 푸시면 프로젝트에서 Status를 In Review로 설정해주세요.
  • 코드 검토자 1분 이상으로부터 승인을 받으셨다면 PR을 병합해주세요.

@Sunjae95 Sunjae95 self-assigned this Sep 20, 2024
@github-actions github-actions bot added the js label Sep 20, 2024
@Sunjae95 Sunjae95 marked this pull request as ready for review September 20, 2024 13:32
@Sunjae95 Sunjae95 requested a review from a team as a code owner September 20, 2024 13:32
Comment on lines +15 to +28
const dfs = (index) => {
if (memo[index] !== -1) return memo[index];

let maxLength = 1;

for (let i = index + 1; i < nums.length; i++) {
if (nums[index] < nums[i]) {
maxLength = Math.max(maxLength, 1 + dfs(i));
}
}

memo[index] = maxLength;
return maxLength;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memo[i] = nums[i]를 첫 원소로 가지는 LIS의 길이로 정의하셨군요 ㅎㅎ

저는 memo[i] = nums[i]를 마지막 원소로 가지는 LIS의 길이로 정의해서 풀었는데, 이 둘 중에서 유의미한 차이가 있을까 고민해봤습니다

싱겁게도 별 차이는 없을 것 같다는 결론이지만요... ㅎㅎㅎ 덕분에 머리도 좀 굴려보고 좋았습니다

풀이 잘 보았습니다!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다시 보니 dfs의 재귀호출이 쌓이므로 선재님의 top-down방식이 bottom-up으로 탐색하는 알고리즘보다는 공간 사용량이 조금 더 클 수도 있을 것 같습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

의도한 바는 아니지만 이 문제를 접근할 때 dfs를 사용해야겠다 생각하고 접근했지만 안타깝게도 time limited가 나오더라구요.
손으로 트리그리면서 중복된 부분이 발견되어 memoization을 사용하면 time limited에 걸리지않을까 시도해봤어요.
그러더니 운좋게? 통과하더라구요...ㅎㅎ

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

공간사용량은 최종depths는 동일하지만 case와 방식에 따라 공간사용량이 다르다고 생각해요.

case가 10, 7, 3, 6, 8, 9, 11 인경우
top down시 10, 7, 3에 대한 연산이 이루어지고
bottom up으로 진행시 11에서만 연산이 되어 모든 경우의 수가 발생되어 top down보다 공간을 더 사용한다고 생각해요.

@obzva 님이 의도하신 공간 사용량이 제가 언급한 예시로 해결이 됐을까요? 아니라면 다른 의미였는지 궁금합니다!

Copy link
Contributor

@obzva obzva Sep 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

원래 제가 드리고 싶었던 말은 이거였는데,

  • 재귀를 이용한 top-down: 탐색 수는 bottom-up과 동일하나, 재귀 함수를 이용하기 때문에 재귀 호출 스택만큼의 추가적인 공간 사용
  • 반복문을 이용한 bottom-up: 탐색 수는 top-down과 동일

좀 더 생각해보니 선재님 말씀이 맞다는 걸 알게 되었습니다 감사합니다 :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예를 들어 선재님이 들어주신 case에서 top-down의 경우에는,

// dfs(10)을 반환하기 전까지 깊이 2만큼의 콜스택 사용
dfs(10) 새로 계산
  ∟dfs(11) 계산

// dfs(7)을 반환하기 전까지 깊이 4만큼의 콜스택 사용
dfs(7) 계산
  ∟dfs(8) 계산
    ∟dfs(9) 계산
      ∟dfs(11) memo에서 get
      
// dfs(3)을 반환하기 전까지 깊이 3만큼의 콜스택 사용
dfs(3) 계산
  ∟dfs(6) 계산
    ∟dfs(8) memo
    
dfs(6) memo

dfs(8) memo

dfs(9) memo

dfs(11) memo

Copy link
Contributor

@obzva obzva Sep 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bottom-up으로 가는 경우에는,

// 첫 원소는 LIS의 길이 1
nums  10, 7, 3, 6, 8, 9, 11
memo  1

// 이전 원소들 중에서 현재 원소보다 값이 더 작은 원소에 대해 탐색
// 7보다 작은 원소 없었음
nums  10, 7, 3, 6, 8, 9, 11
memo  1   1  
                  
// 3보다 작은 원소 없었음
nums  10, 7, 3, 6, 8, 9, 11
memo  1   1  1
 
 // 6보다 작은 원소: 3
 // 연산 1번
nums  10, 7, 3, 6, 8, 9, 11
memo  1   1  1  2
                        
 // 8보다 작은 원소: 3, 6
 // 연산 2번
nums  10, 7, 3, 6, 8, 9, 11
memo  1   1  1  2  3
                             
 // 9보다 작은 원소: 3, 6, 8
 // 연산 3번
nums  10, 7, 3, 6, 8, 9, 11
memo  1   1  1  2  3  4
                                  
 // 11보다 작은 원소: 3, 6, 8, 9
 // 연산 4번
nums  10, 7, 3, 6, 8, 9, 11
memo  1   1  1  2  3  4   5

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어머 선재님 말씀대로네요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아하 bottom up 방식은 이렇게 접근할 수 도 있군요..!
저도 저런식으로 풀고싶었는데 식이 명확하게 잡히지 않아 재귀함수를 사용했는데 for문으로 가능한지 몰랐네요.
리뷰감사합니다 :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

두 분의 상당히 깊이있는 대화를 흥미진진하게 읽었습니다. "재귀 + 메모이제이션"과 "동적 계획법" 간의 미묘한 차이를 잘 보여주는 토론라고 생각합니다. @Sunjae95 님께서 짚어주신 데로 연산량은 숫자의 구성에 따라서 아주 케바케일 것 같습니다. @obzva 님께서 짚어주신 데로 "재귀 + 메모이제이션" 구현이 호출 스택도 메모리를 쓰고 호출 결과를 캐싱하는데도 메모리를 써서 상대적으로 공간 효율이 떨어진다는 것에 저도 동의합니다.

어찌됐든 빅오 표현법으로는 둘 다 결국 공간 복잡도가 O(n)이기 때문에, 순수하게 코딩 테스트 관점에서 바라봤을 때는 우열을 가리는 것이 의미가 없을 정도로 두 분 다 훌륭한 답안을 제출하셨고 건강한 토론을 하셨다고 생각합니다. 👏💯🎖️

Comment on lines +25 to +30
const check = {
left: c >= 1 && visited[r][c - 1],
right: c < MAX_C - 1 && visited[r][c + 1],
top: r >= 1 && visited[r - 1][c],
bottom: r < MAX_R - 1 && visited[r + 1][c],
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 방식은 처음 봤습니다 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOOK UP TABLE이라는 방식이에요.
가독성이나 유지보수성으로 좋은 방식인거 같아요!

const visited = Array.from({ length: MAX_R }, (_, i) => {
return Array.from(
{ length: MAX_C },
(_, j) => i === 0 || i === MAX_R - 1 || j === 0 || j === MAX_C - 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 뭘까 했는데, 일종의 프레임을 미리 만들어주는 것 같네요?? 새로운 방식이라 신기합니다 ㅎㅎ

@Sunjae95 Sunjae95 merged commit 879ecd7 into DaleStudy:main Sep 21, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Completed
Development

Successfully merging this pull request may close these issues.

4 participants