[Leetcode] 211. Design Add and Search Words Data Structure

Sungwooยท2024๋…„ 12์›” 3์ผ
0

Algorithm

๋ชฉ๋ก ๋ณด๊ธฐ
21/43
post-thumbnail

๐Ÿ“•๋ฌธ์ œ

[Leetcode] 211. Design Add and Search Words Data Structure

๋ฌธ์ œ ์„ค๋ช…

๋‹จ์–ด ๋“ฑ๋ก๊ณผ ๋‹จ์–ด ๊ฒ€์ƒ‰์„ ํ•  ์ˆ˜ ์žˆ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฌธ์ œ๋‹ค.
์ƒ์„ฑ์ž์™€ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ word๋ฅผ ๋“ฑ๋กํ•˜๋Š”addWord(word) ํ•จ์ˆ˜, ์ž๋ฃŒ๊ตฌ์กฐ์—์„œ word๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” searchWord(word)ํ•จ์ˆ˜๋ฅผ ์™„์„ฑํ•ด์•ผ ํ•œ๋‹ค.
๊ฒ€์ƒ‰ ํ•จ์ˆ˜์—์„œ word๋Š” ์ (.)์„ ์ตœ๋Œ€ 2๊ฐœ๊นŒ์ง€ ํฌํ•จํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ ์€ ๋ชจ๋“  ๋ฌธ์ž๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค.
์˜ˆ๋ฅผ๋“ค์–ด bad๋ผ๋Š” ๋‹จ์–ด๊ฐ€ ์ž๋ฃŒ๊ตฌ์กฐ์— ์กด์žฌํ•  ๋•Œ ..d๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ฉด True๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.


๐Ÿ“ํ’€์ด

์ฒ˜์Œ ๋ฌธ์ œ๋ฅผ ์ ‘ํ–ˆ์„ ๋•Œ ๋‹จ์ˆœํžˆ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ์ฒซ๊ธ€์ž๋กœ ํ›„๋ณด๊ตฐ์„ ์ค„์ธ ํ›„ ==์—ฐ์‚ฐ์„ ํ†ตํ•ด ๋‹จ์–ด๋ฅผ ๋น„๊ตํ•˜๋ ค๊ณ  ํ–ˆ๋‹ค.
ํ•˜์ง€๋งŒ word์— ๋ชจ๋“  ๋ฌธ์ž๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” .์ด ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ผ์ผ์ด ๋น„๊ตํ•ด์•ผ ํ–ˆ๊ณ , ์ด ๋ฐฉ์‹์€ ํฐ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง„๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ๊ทธ๋งŒ๋’€๋‹ค.
๊ทธ๋Ÿฌ๋‹ค Trie๋ผ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ๋‹ค.

Trie

Trie๋Š” ๋ฌธ์ž์—ด์„ ์ €์žฅํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ํƒ์ƒ‰ํ•˜๊ธฐ ์œ„ํ•œ Treeํ˜•ํƒœ์˜ ์ž๋ฃŒ๊ตฌ์กฐ๋‹ค.

์œ„ ๊ทธ๋ฆผ์€ POT, PAST, PASS, PART๋ฅผ ์ €์žฅํ•œ Trie๋‹ค.
์˜ˆ๋ฅผ๋“ค์–ด PART๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค๊ณ  ํ•˜๋ฉด P, A, R, T ์ˆœ์„œ๋กœ ๊ฒ€์ƒ‰ํ•˜๊ฒŒ ๋œ๋‹ค.
์ด ๋•Œ P, A, R ๋…ธ๋“œ๋ฅผ ๊ฑฐ์น˜๋ฉฐ ํƒ์ƒ‰ ํ›„๋ณด๊ตฐ์„ ์ค„์ด๊ฒŒ ๋˜๊ณ  ์ด๋กœ์ธํ•ด ๋‹จ์–ด๋ฅผ ์ผ์ผ์ด ๋น„๊ตํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค ์‹œ๊ฐ„๋ณต์žก๋„ ์ธก๋ฉด์—์„œ ๋” ํšจ์œจ์ ์ด๋‹ค.


๋จผ์ € Trie๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค.

Node

class Node(object):
    def __init__(self, key, data=None):
        self.key = key
        self.data = data
        self.children = {}

๋…ธ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ •๋ณด๋“ค์„ ๊ฐ€์ง„๋‹ค.

  • ๊ฐ’์œผ๋กœ ์ž…๋ ฅ๋  ๋ฌธ์ž์ธ key.
  • ๋ฌธ์ž์—ด์ด ๋๋‚  ๋•Œ ํ•ด๋‹น ๋ฌธ์ž์—ด์„ ์ €์žฅํ•  data. ํ•ด๋‹น ๊ฐ’์œผ๋กœ ๋ฌธ์ž์—ด์ด ์ข…๋ฃŒ๋จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
  • ์ž์‹๋…ธ๋“œ๋ฅผ ์ €์žฅํ•  children.

Trie
์ƒ์„ฑ์ž

    def __init__(self):
        self.head = Node(None)
  • Trie๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ key๊ฐ’์„ ๊ฐ€์ง€์ง€ ์•Š๋Š” head ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

addword

    def addWord(self, word: str) -> None:
        curr = self.head
        for char in word:
            if char not in curr.children:
                curr.children[char] = Node(char)
            curr = curr.children[char]
        curr.data = word
  • curr๊ฐ’์„ head๋กœ ์„ค์ •ํ•ด head ๋…ธ๋“œ๋ถ€ํ„ฐ ํƒ์ƒ‰ ์‹œ์ž‘ํ•œ๋‹ค.
  • ๋ฌธ์ž์—ด์˜ ๋ฌธ์ž๊ฐ€ curr์˜ children์— ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ•ด๋‹น ๋ฌธ์ž๋ฅผ key๊ฐ’์œผ๋กœ ๊ฐ–๋Š” ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑ ํ›„ children์— ์ถ”๊ฐ€ํ•˜๋ฉฐ ํ•˜๋‚˜์”ฉ ๊ฒ€์‚ฌํ•œ๋‹ค.
  • ๋ฌธ์ž์—ด์ด ๋๋‚˜๋ฉด ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ์˜ data๊ฐ’์— ํ•ด๋‹น ๋ฌธ์ž์—ด์„ ์ €์žฅํ•œ๋‹ค.

search

    def search(self, word: str) -> bool:
        curr = self.head
        for char in word:
            if char in curr.children:
                curr = curr.children[char]
            else:
                return False
        if curr.data:
            return True
        else:
            return False
  • curr๊ฐ’์„ head๋กœ ์„ค์ •ํ•ด head ๋…ธ๋“œ๋ถ€ํ„ฐ ํƒ์ƒ‰ ์‹œ์ž‘ํ•œ๋‹ค.
  • ๋ฌธ์ž์—ด์˜ ๋ฌธ์ž๋ฅผ ํ•˜๋‚˜์”ฉ ๋Œ๋ฉด์„œ children์— ์กด์žฌํ•˜๋Š”์ง€ ๊ฒ€์‚ฌํ•œ๋‹ค. ์ค‘๊ฐ„์— ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด False๋ฅผ ๋ฐ˜ํ™˜.
  • ํƒ์ƒ‰์„ ๋งˆ์นœ ํ›„ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ์— data๊ฐ’์ด ์กด์žฌํ•œ๋‹ค๋ฉด True, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด False๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
    data๊ฐ’์ด ํ•„์š”ํ•œ ์ด์œ : ์‚ฌ์ „์— FARM์ด๋ผ๋Š” ๋‹จ์–ด๊ฐ€ ์กด์žฌํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•  ๋•Œ FAR๋ฅผ ๊ฒ€์ƒ‰ํ•œ ๊ฒฐ๊ณผ๋Š” False์ด์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ.

ํ•ด๋‹น Trie์— ๋ชจ๋“  ๋ฌธ์ž๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” .์ด๋ผ๋Š” ๋ฌธ์ œ์˜ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด์„  search ํ•จ์ˆ˜๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋œ๋‹ค.

์ˆ˜์ •๋œ search()

    def search(self, word: str, curr=None) -> bool:
        if not curr:
            curr = self.head
        for i in range(len(word)):
            char = word[i]
            if char == '.':
                for c in curr.children:
                    if self.search(word[i+1:], curr.children[c]):
                        return True
                return False
            elif char in curr.children:
                curr = curr.children[char]
            else:
                return False
        if curr.data:
            return True
        else:
            return False
  • ํƒ์ƒ‰ ์ค‘ .๋ฅผ ๋งŒ๋‚œ๋‹ค๋ฉด ํ•ด๋‹น ๋…ธ๋“œ์˜ ๋ชจ๋“  children๊ฐ’์— ๋Œ€ํ•ด serch ํ•จ์ˆ˜๋ฅผ ์žฌ๊ท€ ์‹คํ–‰ํ•œ๋‹ค. ์ด๋•Œ ํƒ์ƒ‰์ค‘์ธ ๋…ธ๋“œ์˜ ์œ„์น˜๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ๋งค๊ฐœ๋ณ€์ˆ˜ curr๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.


ํ†ต๊ณผ๋Š” ํ–ˆ์ง€๋งŒ ์ข€ ๋А๋ฆฌ๋‹ค.

leetcode์˜ ์ฝ”๋“œ ์ƒ˜ํ”Œ์„ ๋‘˜๋Ÿฌ๋ณด๋‹ค ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ํ™œ์šฉํ•œ ์ฝ”๋“œ๋ฅผ ๋ฐœ๊ฒฌํ•ด ๊ฐ€์ ธ์™€๋ดค๋‹ค.
๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ์“ธ ์ƒ๊ฐ์€ ํ•ด๋ดค์ง€๋งŒ .์˜ ์กด์žฌ๋•Œ๋ฌธ์— ์ฒซ๊ธ€์ž๋ฅผ key๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์„ ๊ฒƒ ๊ฐ™์•„ ํฌ๊ธฐํ–ˆ์—ˆ๋Š”๋ฐ ์ด ์ฝ”๋“œ์—๋Š” ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๋ฅผ key๋กœ ์‚ฌ์šฉํ–ˆ๋‹ค.

์ƒ์„ฑ์ž

    def __init__(self):
        self.trie = defaultdict(set)
        self.visited = dict()
  • trie์™€ visited ๋‘๊ฐœ์˜ ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ๊ฐ€์ง„๋‹ค. trie๋Š” ๋ฌธ์ž์—ด์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋”•์…”๋„ˆ๋ฆฌ, visited๋Š” ์ด์ „์— ๊ฒ€์ƒ‰ํ•œ ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ๊ฒ€์ƒ‰๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•ด ๋˜‘๊ฐ™์€ ๋ฌธ์ž์—ด์„ ๊ฒ€์ƒ‰ํ–ˆ์„ ๋•Œ ๊ฒ€์ƒ‰ ๊ณผ์ •์„ ์ƒ๋žตํ•ด์ค€๋‹ค.

addWord

    def addWord(self, word: str) -> None:
        self.trie[len(word)].add(word)
  • trie์— ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๋ฅผ key๊ฐ’, ๋ฌธ์ž์—ด์„ value๊ฐ’์œผ๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค.

search

    def search(self, word: str) -> bool:
        N = len(word)
        key = (word, len(self.trie[N]))
        if key in self.visited:
            return self.visited[key]

        for candidate in self.trie[N]:
            i, j = 0, 0
            is_found = True
            # both length are supposed to be equal
            while i < len(candidate) and j < len(word):
                if candidate[i] != word[j] and word[j] != ".":
                    is_found = False
                    break
                i += 1
                j += 1
            if is_found:
                self.visited[key] = True
                return True
        self.visited[key] = False
        return False
  • ๋ฌธ์ž์—ด์ด visited์— ์กด์žฌํ•œ๋‹ค๋ฉด, ์ฆ‰ ์ด์ „๊ฒŒ ๊ฒ€์ƒ‰ํ•œ ๊ธฐ๋ก์ด ์žˆ๋‹ค๋ฉด ์ €์žฅํ–ˆ๋˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • trie๋‚ด์—์„œ word์˜ ๊ธธ์ด๊ฐ€ key ๊ฐ’์ธ ๋ฌธ์ž์—ด๋“ค์ด ํ›„๋ณด๊ตฐ์ด ๋œ๋‹ค.
  • ํ›„๋ณด๊ตฐ๊ณผ word๋ฅผ ํ•˜๋‚˜์”ฉ ๋น„๊ตํ•˜๋ฉฐ ๋‹ค๋ฅธ ๋ฌธ์ž๊ฐ€ ์กด์žฌํ•˜๋ฉด ํƒ์ƒ‰์„ ์ข…๋ฃŒํ•˜๊ณ  ๋‹ค๋ฅธ ํ›„๋ณด๊ตฐ๊ณผ์˜ ๋น„๊ต๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.
  • ๊ฒ€์ƒ‰์„ ๋งˆ์น˜๋ฉด visited๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ฒ˜์Œ์— ์ƒ๊ฐํ•œ ํ•˜๋‚˜ํ•˜๋‚˜ ๋น„๊ตํ•˜๋Š” ๋ฐฉ์‹๊ณผ ์œ ์‚ฌํ–ˆ์ง€๋งŒ ๋ฌธ์ž์—ด์˜ ์ฒซ๊ธ€์ž๋ฅผ key๋กœ ๊ฐ€์ ธ์•ผํ•œ๋‹ค๋Š” ์ƒ๊ฐ์— ์‚ฌ๋กœ์žกํ˜€ ๋– ์˜ฌ๋ฆฌ์ง€ ๋ชปํ•œ๋ฐฉ๋ฒ•์ด๋‹ค.
์ถ”๊ฐ€๋กœ ์ด์ „์— ๊ฒ€์ƒ‰ํ–ˆ๋˜ ๋ฌธ์ž์—ด์„ ์ €์žฅํ•ด ์ค‘๋ณต ํƒ์ƒ‰์„ ๋ฐฉ์ง€ํ•ด ์ข€ ๋” ํšจ์œจ์ ์ด๋‹ค.
ํ•˜์ง€๋งŒ ๊ฐ™์€ ๊ธธ์ด์ธ ๋ฌธ์ž์—ด์ด ๋งŽ์€ ๊ฒฝ์šฐ ํšจ์œจ์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๋ฐฉ๋ฒ•์ธ ๊ฒƒ ๊ฐ™๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€