728x90
문제 설명
앞뒤를 뒤집어도 똑같은 문자열을 팰린드롬(palindrome)이라고 합니다.
문자열 s가 주어질 때, s의 부분문자열(Substring)중 가장 긴 팰린드롬의 길이를 return 하는 solution 함수를 완성해 주세요.
예를들면, 문자열 s가 "abcdcba"이면 7을 return하고 "abacde"이면 3을 return합니다.
제한사항
- 문자열 s의 길이 : 2,500 이하의 자연수
- 문자열 s는 알파벳 소문자로만 구성
예상 문제 풀이 방식
1. 완탐 -> 전체 문자열에서 팰린드롬 구하기 or 팰린드롬만 찾기
2. DP
전체 문자열에서 팰린드롬을 구하면, 시간초과가 날 것 같은 느낌이 들지만, 일단 시도해보자.
func solution(_ s:String) -> Int {
let s = s.map { String($0) }
var array = [String]()
func findString(_ num: Int) { // 부분문자열 찾기
for i in 0..<s.count-num {
let temp = Array(s[i...i+num])
if temp == temp.reversed() { // 팰린드롬만 확인
array.append(temp.joined())
break // 현 배열에서 가장 긴 팰린드롬을 찾음.
}
}
}
for i in 0..<s.count {
findString(i)
}
var result = 0
for i in stride(from: array.count-1, through: 0, by: -1) {
let length = array[i].count
if result < length { // 가장 긴 팰린드롬 길이는?
result = length
break
}
}
return result
}
역시나 시간초과. 아무래도 전체 문자열 길이에서부터 찾으려고 하니 정확성 테스트는 문제 없지만, 효율성 검사에서 시간초과가 발생하는 것 같다.
코드를 개선해보자.
풀이1
func solution(_ s:String) -> Int {
var result = 0
func find(_ i: Int, _ s: String) -> String {
let s = s.map { String($0) }
var left = i
var right = i
while (left-1 >= 0) && s[left] == s[left-1] {
left -= 1
}
while (right+1 < s.count) && s[right] == s[right+1] {
right += 1
}
while (left-1 >= 0) && (right+1 < s.count) && s[left-1] == s[right+1] {
left -= 1
right += 1
}
return s[left...right].joined()
}
for i in 0..<s.count {
let palin = find(i, s)
if result < palin.count {
result = palin.count
}
}
return result
}
while문으로, 현재 인덱스의 문자를 기준으로 좌우로 확장해가며 팰린드롬을 찾아냈다.
중간에 팰린드롬이 아닌 문자열이 발견되면 종료되므로, 함수에서 빠르게 탈출할 수 있다.
효율성 테스트에서 500~1000ms 사이의 값이 나오는 게 조금 마음에 안 든다.
dp로도 가능해보이는데, dp로 풀어보자.
풀이2
func solution(_ s:String) -> Int {
var length = s.count
if length == 1 { return 1 }
let s = s.map { String($0) }
var dp = Array(repeating: Array(repeating: false, count: length), count: length)
var left = 0
var right = 0
for i in 1..<length {
// 첫글자(s[i])와 끝글자(s[j])가 같은 글자이며
// 이전에 팰린드롬임이 확인 된 글자이면 이번 글자도 팰린드롬이다.
// 만약 양끝값(s[i]와 s[j])는 같은데, 내부 글자가 팰린드롬이 아니었으면, 확인할 필요 없으므로 (i-j <= 2)범위만 확인한다.
for j in 0..<i where s[i] == s[j] && (dp[j+1][i-1] || i-j <= 2) {
dp[j][i] = true
if i-j > right-left {
left = j
right = i
}
}
}
let result = s[left...right].joined()
return result.count
}
역시 dp가 최고인가..?
효율성 테스트에서 100~130ms 정도로 개선되었다.
이전 풀이 500~1000ms에 비해 5~10배 정도 개선된 것.
하지만 풀이 시간은 배 이상이 들었기 때문에, 좀 더 연습이 필요해보인다.
반응형
'🐣 알고리즘' 카테고리의 다른 글
[백준] Swift - 21610번: 마법사 상어와 비바라기 (0) | 2024.07.04 |
---|---|
[백준] Swift - 24467번: 혼자하는 윷놀이 (1) | 2024.06.13 |
[프로그래머스] Swift - 단속카메라 (LV.3) (0) | 2024.06.08 |
[프로그래머스] Swift - 날짜 비교하기 (LV.0) (0) | 2024.06.06 |
[프로그래머스] Swift - 구명보트 (LV.2) (0) | 2024.06.06 |
댓글