Search
Duplicate
📒

[LeetCode Top 150] 06-1. Implement Trie

상태
완료
수업
Algorithm Solving
주제
LeetCode Top Interview 150
4 more properties
참고

문제해설

문제 로직고민

NOTE
Trie는 Tree를 활용해서 구현할 수 있다.
Trie의 경우 자식노드에 제한이 없다.
여러 자식노드를 처리하기위해 Map구조를 사용한다.
내부 클래스 Node를 생성하고 다음과 같이 구성한다.
Map → 문자별 자식 Node를 가지게한다.
isLast → 마지막 문자열인지 확인한다.
isLast가 필요한 이유는 app, apple의 경우를 검색하는 예시로 알 수 있다.
apple만 넣었는데, app 문자의 경우 모두 탐색이된다. 이때 app의 마지막 p에서 isLast값에 따라 문자가 있는지 확인이 가능하다.

작성코드

NOTE
class Trie { // node 클래스 class Node{ boolean isLast; Map<Character, Node> map; Node(){ map = new HashMap(); this.isLast = false; } } // 가장 최상단 node private Node root; // 트라이 생성자 public Trie() { root = new Node(); } // 트라이 삽입 public void insert(String word) { Node node = root; for(char c : word.toCharArray()){ if(!node.map.containsKey(c)) node.map.put(c, new Node()); node = node.map.get(c); } node.isLast = true; } // 트라이 검색 public boolean search(String word) { Node node = root; for(char c : word.toCharArray()){ if(!node.map.containsKey(c)) return false; node = node.map.get(c); } return node.isLast ? true : false; } // 트라이 접두사 검색 public boolean startsWith(String prefix) { Node node = root; for(char c : prefix.toCharArray()){ if(!node.map.containsKey(c)) return false; node = node.map.get(c); } return true; } }
Java
복사

정답코드

NOTE
class Trie { private Node root; // 최상위 노드 private boolean result; public Trie() { // 최상위 노드 생성 this.root = new Node(); } public void insert(String words) { insert(root, words); } // 재귀호출 통해 문자열 삽입 private void insert(Node root, String words) { if(words.length() == 0) { // 마지막 문자 삽입완료 root.isEndOfWord = true; // 해당 노드는 마지막 문자임을 나타내므로 true 설정 return; } char word = words.charAt(0); // 삽입할 문자열의 첫번째 문자 // 삽입할 문자가 자식노드로 존재하는지 조회 Node child = root.children.get(word); // 이미 존재한다면 삽입할 필요 없음 // 존재하지않는다면, 현재 노드의 새로운 자식노드로 추가 if(child == null) { child = new Node(); root.children.put(word, child); } // 자식노드와 현재 문자를 제외한 다음 문자열 삽입 재귀호출 insert(child, words.substring(1)); } // 재귀호출을 통해 문자열 탐색 public boolean search(String words) { search(root, words); return result; } private void search(Node root, String words) { // 주어진 문자열에 대해 모든 탐색이 완료되었다면 if(words.length() == 0) { // 해당 문자가 마지막 문자임을 나타내는 값을 반환처리 result = root.isEndOfWord; return; } char word = words.charAt(0); Node child = root.children.get(word); if(child == null) { // 주어진 문자열의 문자를 갖는 child가 존재하지 않는다면 탐색 실패 result = false; return; } else { // 주어진 문자열의 문자를 갖는 child가 존재하면 재귀호출 search(child, words.substring(1)); } } // 재귀호출을 통해 접두사 탐색 public boolean startsWith(String prefix) { startsWith(root, prefix); return result; } private void startsWith(Node root, String prefix) { // 주어진 접두사에 대한 탐색이 모두 완료되었을 때 if(prefix.length() == 0) { result = true; return; } char word = prefix.charAt(0); // 주어진 접두사의 문자가 자식노드로 존재하는지 조회 Node child = root.children.get(word); // 접두사의 문자가 자식노드로 존재하지 않는다면 탐색 실패 if(child == null) { result = false; return; } startsWith(child, prefix.substring(1)); } } class Node { public Map<Character, Node> children; // 문자를 key로 갖고 Node를 value로 갖는 자식노드들을 저장할 Map 선언 public boolean isEndOfWord; // 해당 데이터가 단어의 끝나는 지점인지의 여부 public Node() { children = new HashMap<>(); isEndOfWord = false; } }
Java
복사
메모리를 더 효율적으로 사용
toCharArray()를 사용하지 않고, 시작 문자열을 하나씩 자르면서 사용한다. 이 방식으로 하면 char[]과정이 생략되기 떄문에 더 효율적인 시간이 나오는것 같다.
for문이 아닌 재귀를 사용한 부분은 메모리 효율적인 부분에서 크게 상관없는것 같다.
class TrieNode { TrieNode[] children; boolean isEndOfWord; public TrieNode() { children = new TrieNode[26]; // Assuming lowercase English letters isEndOfWord = false; } } public class Trie { private TrieNode root; public Trie() { root = new TrieNode(); } public void insert(String word) { TrieNode node = root; for (char ch : word.toCharArray()) { int index = ch - 'a'; if (node.children[index] == null) { node.children[index] = new TrieNode(); } node = node.children[index]; } node.isEndOfWord = true; } public boolean search(String word) { TrieNode node = root; for (char ch : word.toCharArray()) { int index = ch - 'a'; if (node.children[index] == null) { return false; } node = node.children[index]; } return node.isEndOfWord; } public boolean startsWith(String prefix) { TrieNode node = root; for (char ch : prefix.toCharArray()) { int index = ch - 'a'; if (node.children[index] == null) { return false; } node = node.children[index]; } return true; }}
Java
복사
실행시간이 더 빠른 코드
Map이 아닌 배열을 사용했다.
위의 상황에서는 알파벳만을 생각하기에 26크기의 배열을 선언했지만, 아스키코드 범위인 128로 하면 기존 코드보다 더 범용적이면서 효율적인 코드가 작성될것 같다.