2022. 9. 5. 17:24ㆍ알고리즘/programmers
레벨 3도 앞장을 다 했네요.앞장에서는 우선순위 큐(힙)나 덱과 같은 자료구조나 최소거리 문제, 완전 탐색 같은 주제였는데요.다시 dp를 다뤄볼 때가 온 것 같습니다. 이게 가장 어려운 것 같아요.
같이 한 번 볼까요?
문제 요약
앞뒤를 뒤집어도 똑같은 문자열을 팰린드롬(palindrome)이라고 합니다.
문자열 s가 주어질 때, s의 부분문자열(Substring)중 가장 긴 팰린드롬의 길이를 return 하는 solution 함수를 완성해 주세요.
예를들면, 문자열 s가 "abcdcba"이면 7을 return하고 "abacde"이면 3을 return합니다.
제한사항
- 문자열 s의 길이 : 2,500 이하의 자연수
- 문자열 s는 알파벳 소문자로만 구성
테스트케이스
s | answer |
"abcdcba" | 7 |
"abacde" | 3 |
접근 방법
다양한 접근 방법이 있겠습니다만..
팰린드롬에서 기본적으로 모든 문자를 순회하는 방법은 보통 효율성 테스트에서 걸리게 되어있습니다.
dp를 이용해서 걸러줘야하는데요.
일반적으로 이 문자 s가 회문인지 검사하는 방법은 아래와 같습니다.
(start = 0, end = n - 1) 양 끝 문자가 같은지 비교한다.
(start = 1, end = n - 2) 그 다음 문자가 같은지 비교한다.
...
(start = x, end = x || x + 1) 가장 중간 문자가 같은지 비교한다.
어떤 길이가 최대 길이인지 모르는 상황에서 같은 비교를 몇 번씩이나 해야하는 상황입니다.
이러면, 길이를 기준으로 순회를 하면서, dp를 만들어주면 적은 연산으로 비교가 가능합니다.
dp[start][end] 이렇게 만든 뒤, start와 end가 같은 글자라면 true로 채워줍시다.
이렇게 하면 매번 회문 비교를 위한 루프는 생략할 수 있습니다.
(start = 0, end = n - 1) 양 끝 문자가 같은지 비교한다.
dp[start + 1][end - 1]이 true인지 확인한다.
이렇게 훨씬 적은 연산으로 처리할 수 있겠군요.
정답 코드
function solution(s) {
const n = s.length;
const memo = Array.from({ length: n }, (_, i) => Array.from({ length: n }, (_, j) => i === j));
let answer = 1;
for(let i = 0; i < n - 1; i++) {
if(s[i] === s[i+1]) {
memo[i][i+1] = true;
answer = 2;
}
}
for (let length = 2; length <= n; length++) {
for (let start = 0; start <= n - length; start++) {
const end = start + length - 1;
if (s[start] === s[end] && memo[start + 1][end - 1]) {
memo[start][end] = true
answer = length;
}
}
}
return answer;
}
실행 결과
팁 1. 왜 길이 2는 따로 계산하나요?
// length: 2 인 경우,
memo[i][i + 1]
// length > 2 인 경우,
memo[start + 1][end - 1]
2 이상인 경우에는 index를 1씩줄여가면서 계산이 되는데,
2인 경우만 다릅니다. 그러니, 2일 때는 따로 계산해줘야합니다.
팁 2. memo가 의미하는 건 뭔가요?
memo[start][end]
// start === end 라면 길이가 최소 1입니다.
// start === start + 1 이라면 길이가 최소 2입니다.
start부터 end까지 팰린드롬이라면 true를 넣어줍니다.
초기 세팅으로 길이가 2인 경우까지 직접 초기화를 시켜주고 밑에 루프를 돌면서 갱신해줍니다.
dp 문제는 풀고 나면 별거 없는 것 같은데, 항상 어떻게 자료를 정리해야할까를 오래 고민하게 되네요.
익숙해질때 까지 반복해야겠습니다.
그럼 이만!
'알고리즘 > programmers' 카테고리의 다른 글
[JS] 성격 유형 검사하기: 난 해시맵이 좋아! (0) | 2022.09.08 |
---|---|
[JS] 코딩 테스트 공부 : 공부 팁 X, 카카오 2022 인턴 문제 O (0) | 2022.09.06 |
[JS] 경주로 건설 - 코테 인생 최초로 9000ms대를 만나다! (0) | 2022.09.03 |
[JS] 합승 택시 요금: Do you know Floyd-Warshall? (1) | 2022.09.02 |
[JS] 이중우선순위큐: 비겁한 정렬은 이제 그만! 당당히 힙으로 맞서 싸워! (0) | 2022.08.31 |