Skip to content

Commit de921a8

Browse files
committed
[Gold IV] Title: 전화번호 목록, Time: 876 ms, Memory: 77820 KB -BaekjoonHub
1 parent 599c4a8 commit de921a8

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# [Gold IV] 전화번호 목록 - 5052
2+
3+
[문제 링크](https://www.acmicpc.net/problem/5052)
4+
5+
### 성능 요약
6+
7+
메모리: 77820 KB, 시간: 876 ms
8+
9+
### 분류
10+
11+
자료 구조, 문자열, 정렬, 트리, 집합과 맵, 트라이
12+
13+
### 제출 일자
14+
15+
2025년 9월 10일 13:50:56
16+
17+
### 문제 설명
18+
19+
<p>전화번호 목록이 주어진다. 이때, 이 목록이 일관성이 있는지 없는지를 구하는 프로그램을 작성하시오.</p>
20+
21+
<p>전화번호 목록이 일관성을 유지하려면, 한 번호가 다른 번호의 접두어인 경우가 없어야 한다.</p>
22+
23+
<p>예를 들어, 전화번호 목록이 아래와 같은 경우를 생각해보자</p>
24+
25+
<ul>
26+
<li>긴급전화: 911</li>
27+
<li>상근: 97 625 999</li>
28+
<li>선영: 91 12 54 26</li>
29+
</ul>
30+
31+
<p>이 경우에 선영이에게 전화를 걸 수 있는 방법이 없다. 전화기를 들고 선영이 번호의 처음 세 자리를 누르는 순간 바로 긴급전화가 걸리기 때문이다. 따라서, 이 목록은 일관성이 없는 목록이다. </p>
32+
33+
### 입력
34+
35+
<p>첫째 줄에 테스트 케이스의 개수 t가 주어진다. (1 ≤ t ≤ 50) 각 테스트 케이스의 첫째 줄에는 전화번호의 수 n이 주어진다. (1 ≤ n ≤ 10000) 다음 n개의 줄에는 목록에 포함되어 있는 전화번호가 하나씩 주어진다. 전화번호의 길이는 길어야 10자리이며, 목록에 있는 두 전화번호가 같은 경우는 없다.</p>
36+
37+
### 출력
38+
39+
<p>각 테스트 케이스에 대해서, 일관성 있는 목록인 경우에는 YES, 아닌 경우에는 NO를 출력한다.</p>
40+
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
final class Trie<T: BidirectionalCollection> where T.Element: Hashable {
2+
class Node {
3+
var childList = [T.Element: Node]()
4+
var endOfWord: Bool
5+
6+
init(_ _endOfWord: Bool) {
7+
endOfWord = _endOfWord
8+
}
9+
10+
func hasChild(for c: T.Element) -> Node? {
11+
return childList[c]
12+
}
13+
func addChild(for key: T.Element) -> Node {
14+
let child = Node(false)
15+
childList.updateValue(child, forKey: key)
16+
return child
17+
}
18+
}
19+
20+
let root = Node(false)
21+
22+
func insert(_ word: T) -> Bool {
23+
// 단어를 입력받는다.
24+
// 단어의 알파벳을 순회하며
25+
// 루트노드 부터 해당 알파벳이 존재한다면
26+
// 그냥 쭉쭉 그 노드로 넘기고 현재 탐색 노드를 그 노드의 해당 자식 노드로 교체
27+
// 존재하지 않는다면, 탐색중인 노드에 새 자식 노드를 등록하고 해당 자식 노드로 교체
28+
var currentNode = root
29+
for c in word {
30+
if let child = currentNode.hasChild(for: c) {
31+
currentNode = child
32+
if currentNode.endOfWord { return false }
33+
continue
34+
}
35+
currentNode = currentNode.addChild(for: c)
36+
}
37+
currentNode.endOfWord = true
38+
guard currentNode.childList.isEmpty else { return false }
39+
return true
40+
}
41+
42+
func contains(_ target: T) -> Bool {
43+
var currentNode = root
44+
for element in target {
45+
guard let nextNode = currentNode.hasChild(for: element) else { return false }
46+
currentNode = nextNode
47+
}
48+
return currentNode.endOfWord
49+
}
50+
51+
func hasWordSamePrefix(from target: T) -> Bool {
52+
var currentNode = root
53+
var depth = 1
54+
for element in target {
55+
guard let nextNode = currentNode.hasChild(for: element) else { return false }
56+
if nextNode.endOfWord, depth != target.count {
57+
return true
58+
}
59+
currentNode = nextNode
60+
depth += 1
61+
}
62+
return false
63+
}
64+
65+
@discardableResult
66+
func delete(_ target: T) -> Bool {
67+
var currentNode = root
68+
// 삭제할 대상의 마지막 문자열 노드까지 내려감
69+
for element in target {
70+
guard let nextNode = currentNode.hasChild(for: element) else { return false }
71+
currentNode = nextNode
72+
}
73+
// 마지막 노드까지 내려갔는데, 대상의 끝이 아니라면 삭제 불가
74+
guard currentNode.endOfWord else { return false }
75+
currentNode.endOfWord = false
76+
return true
77+
}
78+
}
79+
80+
let t = Int(readLine()!)!
81+
82+
outer: for _ in 0..<t {
83+
let trie = Trie<String>()
84+
// let n = Int(readLine()!)!
85+
if let input = readLine(), let n = Int(input) {
86+
var isValid = true
87+
for _ in 0..<n {
88+
let line = readLine()!
89+
if !isValid { continue }
90+
if !trie.insert(line) {
91+
isValid = false
92+
}
93+
}
94+
print(isValid ? "YES" : "NO")
95+
}
96+
}

0 commit comments

Comments
 (0)