[LeetCode] 208 Implement Trie (Prefix Tree)

황은하·2021년 7월 16일
0

알고리즘

목록 보기
66/100
post-thumbnail

Description

A trie (pronounced as "try") or prefix tree is a tree data structure used to efficiently store and retrieve keys in a dataset of strings. There are various applications of this data structure, such as autocomplete and spellchecker.

Implement the Trie class:

  • Trie() Initializes the trie object.
  • void insert(String word) Inserts the string word into the trie.
  • boolean search(String word) Returns true if the string word is in the trie (i.e., was inserted before), and false otherwise.
  • boolean startsWith(String prefix) Returns true if there is a previously inserted string word that has the prefix prefix, and false otherwise.

Example 1:

Input
["Trie", "insert", "search", "search", "startsWith", "insert", "search"][], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]

Output
[null, null, true, false, true, null, true]

Explanation
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // return True
trie.search("app"); // return False
trie.startsWith("app"); // return True
trie.insert("app");
trie.search("app"); // return True

Constraints:

  • 1 <= word.length, prefix.length <= 2000
  • word and prefix consist only of lowercase English letters.
  • At most 3 * 10^4 calls in total will be made to insert, search, and startsWith.


풀이

기본적인 트라이를 생성하고, 삽입, 검색, 접두사 찾기를 만드는 문제이다.
우선 트라이와 트라이 안에 들어갈 노드 클래스를 만들어준다.

트라이 노드

  • 자식노드를 적어둘 맵(Map)을 만든다.
  • 해당 단어가 끝임을 표현하기 위한 isEnd를 만든다.

  • 생성자 - 처음 노드가 생길 때 자식을 표현할 해시맵을 새로 만들어준다.
  • 현재 노드의 자식 맵을 반환 할 getChildren()을 만든다.
  • 현재 노드가 끝임을 표현하기 위한 setEnd()를 만든다.
  • 현재 노드가 끝인지를 반환하려고 isEnd()를 만든다.

트라이

  • 루트노드를 선언해둔다.

  • 생성자로 루트노드를 트라이노드로 만들어준다.
  • insert
    • 루트의 자식맵을 가져온다.
    • 단어의 한 문자씩 본다.
    • 현재 단어를 한 문자씩 보는데, 현재 문자가 자식맵에 들어있는지 본다.
      들어있다면 현재 노드를 자식 노드로 변경한다.
      없다면 새로운 노드를 만들어주고 자식맵에 <현재문자, 새로운 노드>를 넣어준다.
      자식맵을 현재 노드의 자식 맵으로 변경한다.
      만약 현재 문자가 마지막 문자일 경우 노드의 끝을 .setEnd()로 설정해준다.
  • search
    • 루트의 자식 맵을 가져온다.
    • 현재 문자가 들어있는지를 나타낼 flag를 만들고 true로 설정한다.
    • 새 노드를 만들어둔다.
    • 현재 단어를 한 문자씩 보는데, 현재 문자가 자식 맵에 들어있는지 본다.
      들어있다면 현재 노드를 자식 노드로 변경한다.
      자식 맵을 현재 노드의 자식 맵으로 변경한다.
      없다면 flag를 false로 바꿔주고 for문을 빠져나온다.
    • flag가 true이고 node가 끝일 때 찾았다고 할 수 있다.
      이 결과를 반환한다.
  • startsWith
    - 루트의 자식 맵을 가져온다.
    - 현재 문자가 들어있는지를 나타낼 flag를 만들고 true로 설정한다.
    - 새 노드를 만들어둔다.
    - 현재 단어를 한 문자씩 보는데, 현재 문자가 자식 맵에 들어있는지 본다.
    들어있다면 현재 노드를 자식 노드로 변경한다. 자식 노드를 현재 노드의 자식 노드로 변경한다.
    없다면 flag를 false로 바꾸고 for문을 빠져나온다.
    - flag값을 반환한다.

    여기서는 앞부분만 같으면 뒷부분은 상관없기 때문에 flag만 true로 나오면 찾은 것이고, false라면 해당되는 단어가 없다는 뜻이라 search랑 비슷하나 조금은 다르다.



코드

class Trie {
    private TrieNode root;

    /** Initialize your data structure here. */
    public Trie() {
        root = new TrieNode();
    }
    
    /** Inserts a word into the trie. */
    public void insert(String word) {
        Map<Character, TrieNode> children = root.getChildren();
        for (int i = 0; i < word.length(); i++) {
            char curLetter = word.charAt(i);
            TrieNode node;
            if (children.containsKey(curLetter)) {
                node = children.get(curLetter);
            } else {
                node = new TrieNode();
                children.put(curLetter, node);
            }
            children = node.getChildren();
            if (i == word.length() - 1) {
                node.setEnd();
            }
        }
    }
    
    /** Returns if the word is in the trie. */
    public boolean search(String word) {
        Map<Character, TrieNode> children = root.getChildren();
        boolean flag = true;
        TrieNode node = null;
        for (int i = 0; i < word.length(); i++) {
            char curLetter = word.charAt(i);
            if (children.containsKey(curLetter)) {
                node = children.get(curLetter);
                children = node.getChildren();
            } else {
                flag = false;
                break;
            }
        }
        return flag && node.isEnd();
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    public boolean startsWith(String prefix) {
        Map<Character, TrieNode> children = root.getChildren();
        boolean flag = true;
        TrieNode node;
        for(int i = 0; i < prefix.length(); i++) {
            char curLetter = prefix.charAt(i);
            if (children.containsKey(curLetter)) {
                node = children.get(curLetter);
                children = node.getChildren();
            } else {
                flag = false;
                break;
            }
        }
        return flag;
    }
}

class TrieNode {
    private Map<Character, TrieNode> children;
    private boolean isEnd;
    
    public TrieNode() {
        children = new HashMap<>();
    }
    
    public Map<Character, TrieNode> getChildren() {
        return this.children;
    }
    
    public void setEnd() {
        this.isEnd = true;
    }
    
    public boolean isEnd() {
        return this.isEnd;
    }
}

/**
 * Your Trie object will be instantiated and called as such:
 * Trie obj = new Trie();
 * obj.insert(word);
 * boolean param_2 = obj.search(word);
 * boolean param_3 = obj.startsWith(prefix);
 */
profile
차근차근 하나씩

0개의 댓글