๊ฐœ์š”

ํŠธ๋ผ์ด

๋ฌธ์ž์—ด์„ ์ €์žฅํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ํƒ์ƒ‰ํ•˜๊ธฐ ์œ„ํ•œย ํŠธ๋ฆฌย ํ˜•ํƒœ

  • ์žฅ๋‹จ์ 
    • ์‹œ๊ฐ„๋ณต์žก๋„๋Š” O(L: ํƒ์ƒ‰ ๋ฌธ์ž์—ด ๊ธธ์ด) ๋กœ, ๋ฌธ์ž ํ•˜๋‚˜ํ•˜๋‚˜ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์— ๋น„ํ•ด ํšจ์œจ์ ์ด๋‹ค.
    • ๊ฐ ๋…ธ๋“œ๋งˆ๋‹ค ์ž์‹์˜ ํฌ์ธํ„ฐ๋ฅผ ๋ชจ๋‘ ์ €์žฅํ•˜๊ณ  ์žˆ์–ด, ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋น„๊ฐ€ ํฌ๋‹ค.

์›๋ฆฌ

ํŠธ๋ผ์ด์˜ ๊ตฌ์กฐ

  1. ๋ฃจํŠธ๋Š” ์•„๋ฌด๋Ÿฐ ๊ฐ’์ด ์—†๋‹ค.
  2. ์‚ฝ์ž…ํ•  ๋ฌธ์ž์—ด์˜ ๋ฌธ์ž๋ฅผ ๊ฐ๊ฐ ๋…ธ๋“œ๋กœ ๋งŒ๋“ค์–ด, ๋ถ€๋ชจ-์ž์‹์œผ๋กœ ์—ฐ๊ฒฐ์ง“๋Š”๋‹ค.
  3. ๋ฌธ์ž์—ด์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž๋Š” ํ•ด๋‹น ๋ฌธ์ž์—ด์˜ ์ข…๋ฃŒ ์ง€์ ์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ”Œ๋ž˜๊ทธ๋ฅผ True๋กœ ์„ค์ •ํ•œ๋‹ค. ์œ„์˜ ๊ทธ๋ฆผ์—์„œ ๋…ธ๋ž€์ƒ‰ ๋…ธ๋“œ๋“ค์€ ๋‹จ์–ด์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์—ฌ์„œ Flag๊ฐ€ True์ด๋‹ค.

๊ตฌํ˜„

ํŠธ๋ผ์ด์˜ ๋…ธ๋“œ

๋…ธ๋“œ์˜ ๊ตฌ์„ฑ์š”์†Œ

3๊ฐ€์ง€์˜ ํ•„์ˆ˜ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

  1. ๋ฌธ์ž ๊ฐ’
  2. ์ž์‹ ๋…ธ๋“œ ํฌ์ธํ„ฐ๋ฅผ ์ €์žฅํ•  ์ž๋ฃŒ๊ตฌ์กฐ(์ฃผ๋กœ ๋”•์…”๋„ˆ๋ฆฌ)
  3. ํ•ด๋‹น ๋…ธ๋“œ๊ฐ€ ๋‹จ์–ด์˜ ๋งˆ์ง€๋ง‰์ธ์ง€ ๋‚˜ํƒ€๋‚ด๋Š” Flag
ํŠธ๋ผ์ด ๋…ธ๋“œ
class TrieNode:
    def __init__(self, character=None):
        self.c = character
        self.children = {} # key: ์ž์‹ ๋…ธ๋“œ์˜ ๋ฌธ์ž, value: ์ž์‹ ๋…ธ๋“œ
        self.is_end = False # ํ•ด๋‹น ๋ฌธ์ž๋ฅผ ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•˜๋Š” ๋ฌธ์ž์—ด ์กด์žฌ ์œ ๋ฌด
 
    def append(self, child_char, child_node):
        self.children[child_char] = child_node
 
    def pop(self, child_char):
        if child_char in self.children:
            del self.children[child_char]

ํŠธ๋ผ์ด ๋ณธ์ฒด

์ดˆ๊ธฐํ™”

ํŠธ๋ผ์ด ์ดˆ๊ธฐํ™”
class Trie:
    def __init__(self):
        self.head = TrieNode()

์กฐํšŒ

ํŠธ๋ผ์ด ์กฐํšŒ
# ์ •ํ™•ํ•œ ๋ฌธ์ž ํƒ์ƒ‰
    def search(self, string):
        current = self.head
        for c in string:
	        # ๋‹ค์Œ ๋ฌธ์ž๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
            if c not in current.children:
                return False
            current = current.children[c]
        # Flag ํ™•์ธ
        return current.is_end

์‚ฝ์ž…

ํŠธ๋ผ์ด ์‚ฝ์ž…
    def add(self, string):
        if len(string) == 0:
            return
            
        current = self.head
        for c in string:
	        # ํ•ด๋‹น ๋ฌธ์ž์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†์œผ๋ฉด ์ถ”๊ฐ€
            if c not in current.children:
                current.children[c] = TrieNode(c)
            current = current.children[c]
        # Flag ์„ค์ •
        current.is_end = True

์‚ญ์ œ

์‚ญ์ œ ๊ธฐ๋Šฅ์ด ์กฐ๊ธˆ ๋ณต์žกํ•˜๋‹ค.

์›๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  1. ๋งˆ์ง€๋ง‰ ๋ฌธ์ž๊นŒ์ง€ ์ˆœํšŒํ•˜๋ฉด์„œ (๋ถ€๋ชจ ๋…ธ๋“œ, ํ˜„์žฌ ๋ฌธ์ž) ์Šคํƒ์„ ๋งŒ๋“ ๋‹ค.
    • ๋…ธ๋“œ๋ฅผ ์—ญ์ˆœ์œผ๋กœ ์ง€์šฐ๊ธฐ ์œ„ํ•จ
  2. ์—ญ์ˆœ์œผ๋กœ ์ž์‹๋…ธ๋“œ์˜ Flag์™€ children ์„ ํ™•์ธํ•˜๋ฉฐ ์‚ญ์ œ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • Flag๊ฐ€ false์ด๊ณ , children์ด ์—†๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋…ธ๋“œ๋ฅผ ์‚ญ์ œ
  3. ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ถ€๋ชจ๋…ธ๋“œ์— ๋Œ€ํ•ด 2๋ฒˆ์„ ๋ฐ˜๋ณตํ•œ๋‹ค.
ํŠธ๋ผ์ด ์‚ญ์ œ
def delete(self, string):
        # (๋ถ€๋ชจ ๋…ธ๋“œ, ๋ฌธ์ž) ์Šคํƒ
        stack = []
        current = self.head
 
        # ์Šคํƒ ์ดˆ๊ธฐํ™”
        for c in string:
            # ์กด์žฌํ•˜๋Š” ๋ฌธ์ž์ธ์ง€ ํ™•์ธ
            if c not in current.children:
                return False
            stack.append((current, c))
            current = current.children[c]
 
        # ์กด์žฌํ•˜๋Š” ๋ฌธ์ž์—ด์ธ์ง€ ํ™•์ธ
        if not current.is_end:
            return False
        
        # Flag ์„ค์ •
        current.is_end = False
 
        # ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์ข…๋ฃŒ
        if current.children:
            return True
        
        # ๋ถ€๋ชจ๋…ธ๋“œ๋กœ ์žฌ๊ท€ ์ง„ํ–‰: ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†๊ณ  Flag๊ฐ€ False์—ฌ์•ผ ํ•œ๋‹ค.
        for parent, char in reversed(stack):
            del parent.children[char]
            if parent.is_end or parent.children:
                break
 
        return True

์ „์ฒด ์ฝ”๋“œ

ํŠธ๋ผ์ด ๊ตฌํ˜„
class TrieNode:
    def __init__(self, character=None):
        self.c = character
        self.children = {}
        self.is_end = False
 
    def append(self, child_char, child_node):
        self.children[child_char] = child_node
 
    def pop(self, child_char):
        if child_char in self.children:
            del self.children[child_char]
 
class Trie:
    def __init__(self):
        self.head = TrieNode()
 
    def add(self, string):
        if len(string) == 0:
            return
        current = self.head
        for c in string:
            if c not in current.children:
                current.children[c] = TrieNode(c)
            current = current.children[c]
        current.is_end = True
        
    def delete(self, string):
        # (๋ถ€๋ชจ ๋…ธ๋“œ, ๋ฌธ์ž) ์Šคํƒ
        stack = []
        current = self.head
 
        # ์Šคํƒ ์ดˆ๊ธฐํ™”
        for c in string:
            # ์กด์žฌํ•˜๋Š” ๋ฌธ์ž์ธ์ง€ ํ™•์ธ
            if c not in current.children:
                return False
            stack.append((current, c))
            current = current.children[c]
 
        # ์กด์žฌํ•˜๋Š” ๋ฌธ์ž์—ด์ธ์ง€ ํ™•์ธ
        if not current.is_end:
            return False
        
        # Flag ์„ค์ •
        current.is_end = False
 
        # ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์ข…๋ฃŒ
        if current.children:
            return True
        
        # ๋ถ€๋ชจ๋…ธ๋“œ๋กœ ์žฌ๊ท€ ์ง„ํ–‰: ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†๊ณ  Flag๊ฐ€ False์—ฌ์•ผ ํ•œ๋‹ค.
        for parent, char in reversed(stack):
            del parent.children[char]
            if parent.is_end or parent.children:
                break
 
        return True
    
    # ์ •ํ™•ํ•œ ๋ฌธ์ž ํƒ์ƒ‰
    def search(self, string):
        current = self.head
        for c in string:
            if c not in current.children:
                return False
            current = current.children[c]
        return current.is_end