문제
명우는 홍준이와 함께 팰린드롬 놀이를 해보려고 한다.
먼저, 홍준이는 자연수 N개를 칠판에 적는다. 그 다음, 명우에게 질문을 총 M번 한다.
각 질문은 두 정수 S와 E(1 ≤ S ≤ E ≤ N)로 나타낼 수 있으며, S번째 수부터 E번째 까지 수가 팰린드롬을 이루는지를 물어보며, 명우는 각 질문에 대해 팰린드롬이다 또는 아니다를 말해야 한다.
예를 들어, 홍준이가 칠판에 적은 수가 1, 2, 1, 3, 1, 2, 1라고 하자.
- S = 1, E = 3인 경우 1, 2, 1은 팰린드롬이다.
- S = 2, E = 5인 경우 2, 1, 3, 1은 팰린드롬이 아니다.
- S = 3, E = 3인 경우 1은 팰린드롬이다.
- S = 5, E = 7인 경우 1, 2, 1은 팰린드롬이다.
자연수 N개와 질문 M개가 모두 주어졌을 때, 명우의 대답을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 수열의 크기 N (1 ≤ N ≤ 2,000)이 주어진다.
둘째 줄에는 홍준이가 칠판에 적은 수 N개가 순서대로 주어진다. 칠판에 적은 수는 100,000보다 작거나 같은 자연수이다.
셋째 줄에는 홍준이가 한 질문의 개수 M (1 ≤ M ≤ 1,000,000)이 주어진다.
넷째 줄부터 M개의 줄에는 홍준이가 명우에게 한 질문 S와 E가 한 줄에 하나씩 주어진다.
출력
총 M개의 줄에 걸쳐 홍준이의 질문에 대한 명우의 답을 입력으로 주어진 순서에 따라서 출력한다. 팰린드롬인 경우에는 1, 아닌 경우에는 0을 출력한다.
내가 푼 풀이
- 처음에는 주어진 질문에대한 모든 경우의 수에서 팰린드롬인지 구하려고 했지만, 수열의 크기를 감안했을 때 시간초과가 날 거라 생각했다.
- dp를 이용하여 dp 배열에 저장하고, 질문들을 해당 배열에서 꺼내오려한다.
- dp에 저장하기 위해 팰린드롬의 성질을 좀 더 생각해봐야 했다.
- 여기서 이용했던 팰린드롬의 성질은 주어진 수열에서 s번째부터 e까지의 수열이 팰린드롬이라면, s+1번째부터 e-1까지의 수열도 역시 팰린드롬이 된다.
- 예로 위에 주어진 수열 1, 2, 1, 3, 1, 2, 1에서 0번째부터 6번째까지의 수열이 1, 2, 1, 3, 1, 2, 1이고, 해당 수열은 팰린드롬이다.
- 0번째부터 6번째까지의 수열이 팰린드롬이라면, 1번째부터 5번째까지의 수열도 역시 팰린드롬이다. ( 2, 1, 3, 1, 2 )
- 위의 성질을 이용하기 위해선 주어진 수열의 길이가 최소 3이어야 한다.
- 수열의 길이가 1이라면 원소 자기 자신하나로 팰린드롬이 된다.
- 수열의 길이가 2라면 원소 하나와 그다음 원소가 같다면, 팰린드롬이 된다.
- 수열의 길이가 3 미만인 경우의 수는 위와 같이 구하고, 3 이상인 경우는 아래와 같이 구한다.
- dp [i][j] = i번째부터 j번째까지의 수열이 팰린드롬인가? ( 팰린드롬이라면 1을 저장, 아니라면 0을 저장)
- 위 성질을 이용하여 수열의 길이가 3이상이라면, 두가지 경우의 수를 판단하면된다.
1. 수열의 양 끝 원소가 같은지?
2. 주어진 수열의 s+1번째부터 e-1까지의 수열이 팰린드룸인지?
해당 문제는 많은 입력과 출력을 요구하므로, readLine을 이용한 입력및 print 출력을 남용하면 시간초과가 뜬다.
더 빠른 FileIO를 이용하여 입력 및 한 문자열에 저장하여 한번에 출력하는 방식을 이용한다.
코드로 구현해보자.
import Foundation
// Swift 입출력
final class FileIO {
private var buffer:[UInt8]
private var index: Int
init(fileHandle: FileHandle = FileHandle.standardInput) {
buffer = Array(fileHandle.readDataToEndOfFile())+[UInt8(0)]
index = 0
}
@inline(__always) private func read() -> UInt8 {
defer { index += 1 }
return buffer.withUnsafeBufferPointer { $0[index] }
}
@inline(__always) func readInt() -> Int {
var sum = 0
var now = read()
var isPositive = true
while now == 10
|| now == 32 { now = read() }
if now == 45{ isPositive.toggle(); now = read() }
while now >= 48, now <= 57 {
sum = sum * 10 + Int(now-48)
now = read()
}
return sum * (isPositive ? 1:-1)
}
@inline(__always) func readString() -> String {
var str = ""
var now = read()
while now == 10
|| now == 32 { now = read() }
while now != 10
&& now != 32 && now != 0 {
str += String(bytes: [now], encoding: .ascii)!
now = read()
}
return str
}
}
// 입력
let fileIO = FileIO()
let N = fileIO.readInt()
var arr = [Int]()
for i in 0..<N {
arr.append(fileIO.readInt())
}
let M = fileIO.readInt()
var dp = Array(repeating: Array(repeating: 0, count: N), count: N)
// 수열의 길이가 1일때
for i in 0..<N {
dp[i][i] = 1
}
// 수열의 길이가 2일때
for i in 0..<N-1 {
if arr[i] == arr[i+1] {
dp[i][i+1] = 1
}
}
// 수열의 길이가 3이상일때
for i in (0..<N-2).reversed() {
for j in (i+2..<N).reversed() {
let idx = j
if arr[i] == arr[idx] && dp[i+1][idx-1] == 1 {
dp[i][idx] = 1
}
}
}
var answer = ""
for i in 0..<M {
let s1 = fileIO.readInt()
let s2 = fileIO.readInt()
answer += "\(dp[s1-1][s2-1])\n"
}
print(answer)
'코딩테스트 > 백준' 카테고리의 다른 글
BOJ-11403 경로 찾기 Swift (0) | 2023.07.01 |
---|---|
BOJ-1417 국회의원 선거 Swift (0) | 2023.07.01 |
BOJ-2206 벽 부수고 이동하기 Swift (0) | 2023.06.30 |
BOJ-16435 스네이크버드 Swift (0) | 2023.06.29 |
BOJ-14002 가장 긴 증가하는 부분 수열 4 Swift (0) | 2023.06.29 |