문제
https://www.acmicpc.net/problem/1032
백준 유의사항
- readLine()을 통해 input을 취득해야 한다.
- Input이 여러줄인 경우, readLine()이 nil 일 때까지 값을 취득해야 한다.
- 백준 온라인 저지의 Swift 컴파일러가 지원하지 않는 버전의 문법이 포함되어있는 경우, 컴파일 에러가 발생할 수 있다.
// e.g. 옵셔널 바인딩 문법
guard let value else { return } // Swift 5.7 이상에서 지원, ❌
guard let value = value else { return } // ✅
제출 코드
var lines: [String] = []
while let line = readLine() {
lines.append(line)
}
func run(input: [String]) -> String {
// 파일 개수가 1개라면 유일한 파일 이름 반환
guard Int(input[0]) ?? 0 > 1 else { return input.last ?? "" }
// "파일 이름 문자열 -> 문자 배열" 변환
let characterSet = input[1..<input.count].map({ $0.map({ $0 }) })
var result: [Character] = []
// 모든 파일명의 길이가 같다는 전제가 있기 때문에 파일명의 길이만큼만 순환
Array(0..<(characterSet.first?.count ?? 0)).forEach { index in
var comparedChar: Character?
for chars in characterSet {
// 첫 문자라면 저장
guard comparedChar != nil else {
comparedChar = chars[index]
continue
}
// 첫 문자가 아니라면 비교하고, 문자가 다르면 패턴이 아니기 때문에 "?" 저장하고 순환 종료
if comparedChar != chars[index] {
comparedChar = "?"
break
}
}
// 문자 인덱스 별 결과 문자를 최종 문자 배열에 추가
guard let comparedChar = comparedChar else { return }
result.append(comparedChar)
}
// "문자 배열 -> 문자열" 병합
return result.map({ String($0) }).joined()
}
print(run(input: lines))
개선 코드
// 파일 개수를 먼저 캐치하기
if let firstLine = readLine(), let fileCount = Int(firstLine) {
var files: [String] = []
while let file = readLine() {
files.append(file)
}
let firstFile = files[0]
if fileCount == 1 {
print(firstFile)
} else {
var result: String = "" // "문자 배열 -> 문자열" 수정
let length = firstFile.count
for index in 0..<length {
let stringIndex = firstFile.index(firstFile.startIndex, offsetBy: index) // String.Index
let referenceChar = firstFile[stringIndex] // 문자열 접근 가능
var isMatched: Bool = true // "result에 추가할 문자 저장 -> 패턴 해당 여부" 수정
for file in files[1...] {
let fileStringIndex = file.index(file.startIndex, offsetBy: index) // String.Index
if file[fileStringIndex] != referenceChar { // 문자열 접근 가능
isMatched = false
break
}
}
result.append(isMatched ? referenceChar : "?")
}
print(result)
}
}
개선된 점
- 입력 저장
- 개선 전
- 전체 입력을 배열로 저장
- 개선 후
- 첫번째 입력라인은 파일갯수(숫자)이기 때문에 첫번째 입력을 fileCount로 별도 저장하고, 이후 입력값은 파일명이기 때문에 files: [String]으로 저장
- 필요한 값이 역할에 맞게 분리되어 저장되어 배열에 접근하는 등의 처리를 하지 않아 가독성이 향상되었습니다.
- 개선 전
- 문자 배열 변환 & 결과 저장
- 개선 전
- String 내 문자 배열에 Int 타입으로 접근할 수 없어 문자 배열로 변환
- 개선 후
- String.Index 타입의 인덱스를 구해 문자 배열 변환없이 바로 문자열에 subscript로 접근하여 해당 위치에 존재하는 문자 추출
- startIndex로부터 offsetBy 값만큼 떨어진 인덱스 위치의 값을 구할 수 있기 때문에 index로 원하는 위치의 문자 추출 가능
- 문자열에서 문자 배열로 변환하여 저장하면 O(N * L) 의 추가 공간을 사용하지만, 추가 변환없이 문자열을 그대로 사용하고 result도 문자배열이 아닌 문자열로 처리하게되어 최소한 O(L) 의 추가 공간 아용으로 메모리 효율이 개선되었습니다. (N : 파일 개수, L : 파일명 길이)
- 개선 전
- 시간 복잡도는 파일 길이(L)만큼 반복하고, 각 반복마다 파일 개수(N)를 순회하는 것은 동일하기 때문에 O(N · L) 로 같지만, 파일 문자열을 문자 배열로 변환하는 작업이 제거되어 상수 시간 즉 각 문자마다 발생할 수 있는 O(1) 시간들이 줄어들기 때문에 최적화가 되었다고 볼 수 있습니다.
| 개선 전 | 개선 후 | |
| 시간복잡도 | O(N * L) + a a : 문자열 → 문자배열 반환으로 인한 상수 시간 |
O(N * L) |
| 공간복잡도 | O(N * L) | O(L) |
상수 시간 오버헤드 개념은 처음 접한 개념이라서 최대한 이해한대로 작성했습니다.
반응형
'알고리즘' 카테고리의 다른 글
| leetcode 225. Implement Stack using Queues 문제 풀이 (0) | 2025.04.04 |
|---|---|
| leetcode 232. Implement Queue using Stacks 문제 풀이 (0) | 2025.04.03 |
| 백준 31458번 문제 풀이 (0) | 2025.04.02 |
| 백준 10820번 문제 풀이 (0) | 2025.04.01 |
| 백준 10988번 문제 풀이 (0) | 2025.04.01 |