BAEKJOON #5052번 전화번호 목록 (문자열) - python

전화번호 목록

출처 : 백준 #5052

시간 제한메모리 제한
1초256MB

문제

전화번호 목록이 주어진다. 이때, 이 목록이 일관성이 있는지 없는지를 구하는 프로그램을 작성하시오.

전화번호 목록이 일관성을 유지하려면, 한 번호가 다른 번호의 접두어인 경우가 없어야 한다.

예를 들어, 전화번호 목록이 아래와 같은 경우를 생각해보자

  • 긴급전화: 911
  • 상근: 97 625 999
  • 선영: 91 12 54 26
    이 경우에 선영이에게 전화를 걸 수 있는 방법이 없다. 전화기를 들고 선영이 번호의 처음 세 자리를 누르는 순간 바로 긴급전화가 걸리기 때문이다. 따라서, 이 목록은 일관성이 없는 목록이다.

입력

첫째 줄에 테스트 케이스의 개수 t가 주어진다. (1 ≤ t ≤ 50) 각 테스트 케이스의 첫째 줄에는 전화번호의 수 n이 주어진다. (1 ≤ n ≤ 10000) 다음 n개의 줄에는 목록에 포함되어 있는 전화번호가 하나씩 주어진다. 전화번호의 길이는 길어야 10자리이며, 목록에 있는 두 전화번호가 같은 경우는 없다.


출력

각 테스트 케이스에 대해서, 일관성 있는 목록인 경우에는 YES, 아닌 경우에는 NO를 출력한다.


입출력 예시

예제 입력 1

2
3
911
97625999
91125426
5
113
12340
123440
12345
98346

예제 출력 1

NO
YES


풀이

생각 및 풀이 설명

  • 처음에는 단순히 이중 for문을 통해 짧은 문자열이 긴 문자열의 앞 부분에 속하는지 여부를 판단했다.

  • 당연히 오답이다. (시간초과)

  • 도저히 생각이 안나서 질문검색 페이지를 보니 Trie? 알고리즘을 통해 풀었다고 했다.

  • 사실 해당 알고리즘을 찾아서 완벽히 숙지 후 풀어도 됐겠지만, 자존심이 허락하지 않았다.

  • 따라서 트리로 접근한다는 사실만을 캐치하고 내 스스로 코드를 짜보았다.

  • 핵심은 문자열이 끝날 때마다 flag를 심어주어서 다른 문자열을 트리에 넣을 때 해당 flag를 지나치는지 여부로 판단하는 것이다.

  • 설명이 어렵다면 아래의 그림을 참고하여 보자.

  • 우선 Node 클래스에 next 공간을 만들어 주었다.

    • 번호는 0~9까지 있을 수 있으므로 공간은 10씩 할당하였다.
    • 또한 flag를 심어서 초기값을 False로 놓았다.
  • Graph 클래스에서는 탐색의 처음에 사용할 adjList를 선언했고, 마찬가지로 0~9까지 올 수 있다고 판단하여 10만큼의 공간을 할당했다.

    • insertEdge 함수를 통해 만약 첫 숫자가 없을 경우 노드를 생성하여 해당 숫자를 인덱스로 가진 곳에 넣어주었다.
    • 첫 숫자의 공간에 노드가 존재할 경우 이를 따라 내려가도록 했다.
    • flag를 도중에 만나면 멈추는 식으로 만들었다.
  • 이렇게 하면 1개의 번호일 때 체클르 못해주어서 1개의 문자열이 들어올 때 flag를 심어주는 if문도 넣었다.

  • 문자열 문제를 요즘 많이 풀면서 느낀 것은 다양한 자료구조를 통해 시각화를 할 수 있거나 반대 방향으로 탐색하면 조금 더 쉽게 문제를 접근할 수 있었다는 사실이다.

  • 많이 부족했지만 그래도 끝까지 답을 안보고 스스로 코드를 작성해보는 계기가 되었고, 앞으로는 다양한 자료구조도 함께 생각해보는 사람이 되어야겠다.

python code

# 백준 5052번 전화번호 목록
from sys import stdin
input = stdin.readline

class Node:
    def __init__(self, node):
        self.node = node
        self.next = [None]*10
        self.flag = False

class Graph:
    def __init__(self):
        self.adjList = [0] * 10
    
    def insertEdge(self, string):
        x = int(string[0])
        if self.adjList[x] == 0:
            new = Node(x)
            self.adjList[x] = new
   
        
        temp = self.adjList[x]
        if len(string) == 1:
            temp.flag = True
        else:
            if temp.flag == True:
                return False
        for i in range(1, len(string)):
            S = int(string[i])
            if temp.next[S] is None:
                w = Node(S)
                temp.next[S] = w
            else:
                if temp.next[S].flag != False:
                    return False
            if i == len(string)-1: # 마지막 원소라면
                temp.next[S].flag = True
            temp = temp.next[S]
        return True
                

def solution(phonebook):
    phonebook.sort()
    n = len(phonebook)
    g = Graph()
    for number in phonebook:
        result = g.insertEdge(number)
        if result != True:
            return "NO"
    return "YES"


    # 시간 초과
    # for i in range(n):
    #     for j in range(i+1, n):
    #         m = len(phonebook[i]) 
    #         if len(phonebook[i]) < len(phonebook[j]):
    #             if phonebook[j][:m] == phonebook[i]:
    #                 return "NO"
    # return "YES"


t = int(input())
for x in range(t):
    n = int(input())
    phonebook = []
    for i in range(n):
        phonebook.append(input().rstrip())
    print(solution(phonebook))

좋은 웹페이지 즐겨찾기