๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ Algorithm/์•Œ๊ณ ๋ฆฌ์ฆ˜-Swift

[์•Œ๊ณ ๋ฆฌ์ฆ˜/Swift] BOJ 14725 ๊ฐœ๋ฏธ๊ตด :: ๋ฌธ์ž์—ด, ํŠธ๋ผ์ด ํŠธ๋ฆฌ (Trie Tree)

by Danna 2021. 5. 26.
728x90
728x90

์•Œ๊ณ ๋ฆฌ์ฆ˜ ์Šคํ„ฐ๋”” ์ง€๋‚œ์ฃผ ์ฃผ์ œ๋Š” "๋ฌธ์ž์—ด" ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ํŠธ๋ผ์ด ํŠธ๋ฆฌ๋ฅผ ํ™œ์šฉํ•œ ๋ฌธ์ œ๊ฐ€ ์ธ์ƒ์ ์ด์—ˆ๊ณ , ๋งŽ์ด ํ™œ์šฉ๋˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ์ฃผ Swift ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ฑ…์—์„œ๋„ ํŠธ๋ฆฌ ์ค‘, ํŠธ๋ผ์ด ํŠธ๋ฆฌ๋ฅผ ๊ณต๋ถ€ํ•ด์„œ ์ •๋ฆฌํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค!

 

14725๋ฒˆ: ๊ฐœ๋ฏธ๊ตด

์ฒซ ๋ฒˆ์งธ ์ค„์€ ๋กœ๋ด‡ ๊ฐœ๋ฏธ๊ฐ€ ๊ฐ ์ธต์„ ๋”ฐ๋ผ ๋‚ด๋ ค์˜ค๋ฉด์„œ ์•Œ๊ฒŒ ๋œ ๋จน์ด์˜ ์ •๋ณด ๊ฐœ์ˆ˜ N๊ฐœ๊ฐ€ ์ฃผ์–ด์ง„๋‹ค.  (1 ≤ N ≤ 1000) ๋‘ ๋ฒˆ์งธ ์ค„๋ถ€ํ„ฐ N+1 ๋ฒˆ์งธ ์ค„๊นŒ์ง€, ๊ฐ ์ค„์˜ ์‹œ์ž‘์€ ๋กœ๋ด‡ ๊ฐœ๋ฏธ ํ•œ๋งˆ๋ฆฌ๊ฐ€ ๋ณด๋‚ด์ค€ ๋จน์ด

www.acmicpc.net

 

๐Ÿ‘€ ํ’€์ด ๋ฐฉ๋ฒ•

์ด ๋ฌธ์ œ์—์„œ๋Š” ์•„๋ž˜ ๊ทธ๋ฆผ์œผ๋กœ ํžŒํŠธ๋ฅผ ์คฌ์–ด์š”. ์ฒ˜์Œ ๋ฌธ์ œ๋ฅผ ๋ดค์„ ๋• ํŠธ๋ผ์ด ํŠธ๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋Š” ์ƒํƒœ์˜€์ง€๋งŒ, ์•„.. ๋ญ”๊ฐ€ ํŠธ๋ฆฌ๊ตฌ์กฐ๋ฅผ ํ™œ์šฉํ•ด์•ผํ•˜๋Š” ๊ตฌ๋‚˜๋ฅผ ์•Œ๊ฒŒ ๋˜์—ˆ์ฃ ! ๊ทธ๋ž˜์„œ ์ฐพ์•„๋ณด๋‹ˆ, ํŠธ๋ผ์ด ํŠธ๋ฆฌ๋ฅผ ํ™œ์šฉํ•ด์„œ ํ‘ธ๋Š” ๋ฌธ์ œ๋ผ๋Š” ๊ฑธ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ’ก ํŠธ๋ผ์ด ํŠธ๋ฆฌ (Trie Tree) ?
ํŠธ๋ผ์ด ํŠธ๋ฆฌ๋Š” ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰์— ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค. ๋ชจ์„œ๋ฆฌ(Edge) ์— Key ๋ฅผ ์ง€๋‹ˆ๊ณ , ๋…ธ๋“œ์˜ ๋ชจ๋“  ์ž์†์€ ๋…ธ๋“œ์— ์—ฐ๊ด€๋œ ๋ฌธ์ž์—ด์˜ ๊ณตํ†ต ์ ‘๋‘์‚ฌ(Prefix)๋ฅผ ๊ณต์œ ํ•œ๋‹ค. Prefix Tree ๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค.

๊ฐœ๋ฏธ๊ตด ์˜ˆ์‹œ ์ด๋ฏธ์ง€

โœ”๏ธŽ ์ž…·์ถœ๋ ฅ

๊ฐœ๋ฏธ๊ตด ๋ฌธ์ œ๋Š” ์ž…๋ ฅ๋œ ์ „์ฒด ๋ฌธ์ž์—ด์„ ๋„์–ด์“ฐ๊ธฐ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋…ธ๋“œ๋ฅผ ๊ตฌ๋ถ„ํ•ด ์‚ฝ์ž…ํ•˜๊ณ , ์ด๋ฅผ ์‹œ๊ฐํ™”ํ•ด์„œ ์ถœ๋ ฅํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. 

์ž… / ์ถœ๋ ฅ

 

โœ”๏ธŽ Swift ์ฝ”๋“œ

ํŠธ๋ผ์ด ํŠธ๋ฆฌ๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋“œ์™€ ํŠธ๋ฆฌ ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ , ์‚ฝ์ž…๊ณผ ์ „์ฒด ํŠธ๋ฆฌ๋ฅผ ํƒ์ƒ‰ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

import Foundation

class TrieNode {
    var key: String?
    weak var parent: TrieNode?
    var children: [String: TrieNode] = [:]
    var isLeaf: Bool {
        return children.isEmpty
    }
    
    init(key: String? = nil, parent: TrieNode? = nil) {
        self.key = key
        self.parent = parent
    }
}

class TrieTree {
    // ํŠธ๋ผ์ด ํŠธ๋ฆฌ์˜ ๋ฃจํŠธ์˜ key ๋Š” nil์ด๋‹ค.
    let root: TrieNode
    
    init() {
        root = TrieNode()
    }
    
    // ์ž…๋ ฅ ๋ฌธ์ž์—ด์„ ํ†ตํ•ด ๋…ธ๋“œ๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ๋ฉ”์†Œ๋“œ
    func insert(words: [String]) {
        var currentNode = root
        let n = Int(words[0])!
        for word in words[1...n] {
            
            // ๋‹จ์–ด๊ฐ€ ํ˜„์žฌ ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ์— ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ -> ํ˜„์žฌ ๋…ธ๋“œ ๋ณ€๊ฒฝ
            if let childNode = currentNode.children[word] {
                currentNode = childNode
            }
            
            // ๋‹จ์–ด๊ฐ€ ํ˜„์žฌ ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ 
            // -> ๋…ธ๋“œ ์ƒ์„ฑ, ์ž์‹ ๋…ธ๋“œ ์ถ”๊ฐ€, ํ˜„์žฌ ๋…ธ๋“œ ๋ณ€๊ฒฝ
            else {
                let newNode = TrieNode(key: word, parent: currentNode)
                currentNode.children[word] = newNode
                currentNode = newNode
            }
        }
    }
    
    // ํŠธ๋ผ์ด ํŠธ๋ฆฌ๋ฅผ ์ „์ฒด์ ์œผ๋กœ ํƒ์ƒ‰ํ•˜๋Š” ๋ฉ”์†Œ๋“œ
    func traversal(node: TrieNode, depth: Int) {
        
        // ํŠธ๋ฆฌ์˜ ๊ณ„์ธต์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•œ ์ถœ๋ ฅ๋ฌธ - root๋ฅผ ์ œ์™ธํ•œ ๋ชจ๋“  ๋…ธ๋“œ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.
        if let key = node.key {
            var dash: String = ""
            for _ in 0..<depth {
                dash += "--"
            }
            print(dash + key)
        }
        
        // ์žŽ์‚ฌ๊ท€ ๋…ธ๋“œ์ธ ๊ฒฝ์šฐ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœ๋œ ๋ฉ”์†Œ๋“œ๋ฅผ ์ข…๋ฃŒํ•œ๋‹ค.
        guard !node.isLeaf else {
            return
        }
        // ๋…ธ๋“œ์˜ ์ž์‹๋“ค์„ ์‚ฌ์ „์ˆœ์œผ๋กœ ํƒ์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ์ •๋ ฌํ•œ๋‹ค.
        let sortedChildren = node.children.sorted(by: {$0.0 < $1.0})
        
        // ๋…ธ๋“œ์˜ ์ž์‹๋“ค์„ ์žฌ๊ท€์ ์œผ๋กœ ํƒ์ƒ‰ํ•œ๋‹ค.
        for child in sortedChildren {
            traversal(node: child.value, depth: depth + 1)
        }
    }
}

// ์ž…๋ ฅ๊ณผ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋“ฑ
let N = Int(readLine()!)!
let trie = TrieTree()
for _ in 0..<N {
    let line = readLine()!.split(separator: " ").map{String($0)}
    trie.insert(words: line)
}
trie.traversal(node: trie.root, depth: -1)

 

Python3 ์ฝ”๋“œ

์ฒ˜์Œ์— Python ์œผ๋กœ ํ’€์ด๋ฅผ ์‹œ์ž‘ํ–ˆ์–ด์„œ ์ฐธ๊ณ ์šฉ์œผ๋กœ ์˜ฌ๋ ค๋‘ก๋‹ˆ๋‹ค :)

class Node:
    # key - ๋…ธ๋“œ์˜ ํ‚ค, data : ์ „์ฒด ๋ฌธ์ž์—ด, children : ์ž์‹ ๋…ธ๋“œ ๋”•์…”๋„ˆ๋ฆฌ
    def __init__(self, key, data=None):
        self.key = key
        self.data = data
        self.depth = 0
        self.children = {}

class Trie:
    def __init__(self):
        self.head = Node(None)
    
    def insert(self, string):
        current_node = self.head
        depth = 0
        for s in string.split(' '):
            # ์ƒˆ๋กœ์šด ๋ฌธ์ž๊ฐ€ ๋…ธ๋“œ์˜ ํ•˜์œ„์— ์—†๋Š” ๊ฒฝ์šฐ, ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ์ƒ์„ฑ
            if s not in current_node.children:
                current_node.children[s] = Node(s)
            # ํ˜„์žฌ ๋…ธ๋“œ๋ฅผ ๋ณ€๊ฒฝ
            current_node = current_node.children[s]
            current_node.depth = depth
            #print(current_node.key, current_node.data == None)
            depth += 1
        # ํ•˜๋‹จ ๋…ธ๋“œ์— ์ „์ฒด ๋ฌธ์ž์—ด์„ ์ €์žฅ
        current_node.data = string
        #print(current_node, current_node.data == None)

    def traversal(self, current_node):
        #current_node = self.head
        if current_node.data:
            return

        children = sorted(current_node.children.keys())
        for c in children:
            depth = current_node.children[c].depth
            print('--'*depth, end='')
            print(c)
            self.traversal(current_node.children[c])

N = int(input())
trie = Trie()
for _ in range(N):
    data = input().split()
    data = ' '.join(data[1:])
    trie.insert(data)

trie.traversal(trie.head)
728x90
728x90