データ構造09バンド|JS

24888 ワード


画像ソース

Trie | Trie

  • 文字列における高速検索を支援するデータ構造
  • 整数型でバイナリプローブツリーを使用する場合、時間複雑度O(logn)
    ただし、文字列に適用する場合、文字列の最大長がMの場合はO(M*logn)となります.
    明るい映画を利用すると?→O(M)を使って文字列を検索できます!
  • 3ノード実装

    import HashTable from '../hash-table/HashTable';
    
    export default class TrieNode {
      constructor(character, isCompleteWord = false) {
        this.character = character;
        this.isCompleteWord = isCompleteWord;
        this.children = new HashTable();
      }
    
      getChild(character) {
        return this.children.get(character);
      }
    
      addChild(character, isCompleteWord = false) {
        if (!this.children.has(character)) {
          this.children.set(character, new TrieNode(character, isCompleteWord));
        }
    
        const childNode = this.children.get(character);
    
        // ex) "carpet" 뒤에 "car"를 추가하는 경우 "r" 문자를 완성으로 표시해야 함
        childNode.isCompleteWord = childNode.isCompleteWord || isCompleteWord;
    
        return childNode;
      }
    
      removeChild(character) {
        const childNode = this.getChild(character);
    
        // childNode에 children이 없고
        // && childNode가 CompleteWord가 아닐 경우에만 삭제
        if (
          childNode
          && !childNode.isCompleteWord
          && !childNode.hasChildren()
        ) {
          this.children.delete(character);
        }
    
        return this;
      }
    
      hasChild(character) {
        return this.children.has(character);
      }
    
      hasChildren() {
        return this.children.getKeys().length !== 0;
      }
    
      suggestChildren() {
        return [...this.children.getKeys()];
      }
    
      toString() {
        let childrenAsString = this.suggestChildren().toString();
        childrenAsString = childrenAsString ? `:${childrenAsString}` : '';
        const isCompleteString = this.isCompleteWord ? '*' : '';
    
        return `${this.character}${isCompleteString}${childrenAsString}`;
      }
    }

    ストライプロジックの実装

    import TrieNode from './TrieNode';
    
    // 트라이 트리의 루트에 사용할 문자
    const HEAD_CHARACTER = '*';
    
    export default class Trie {
      constructor() {
        this.head = new TrieNode(HEAD_CHARACTER);
      }
    
      addWord(word) {
        const characters = Array.from(word);
        let currentNode = this.head;
    
        for (let charIndex = 0; charIndex < characters.length; charIndex += 1) {
          const isComplete = charIndex === characters.length - 1;
          currentNode = currentNode.addChild(characters[charIndex], isComplete);
        }
    
        return this;
      }
    
      deleteWord(word) {
        const depthFirstDelete = (currentNode, charIndex = 0) => {
          if (charIndex >= word.length) {
            return; // 단어의 범위를 벗어난 문자를 삭제하려는 경우 반환
          }
    
          const character = word[charIndex];
          const nextNode = currentNode.getChild(character);
    
          if (nextNode == null) {
            return; // 트리에 추가되지 않은 단어를 삭제하려는 경우 반환
          }
    
          // Go deeper.
          depthFirstDelete(nextNode, charIndex + 1);
    
          // 마지막 character의 isCompleteWord flag는 false로 설정
          if (charIndex === (word.length - 1)) {
            nextNode.isCompleteWord = false;
          }
    
          // childNode에 children이 없고
          // && childNode가 CompleteWord가 아닐 경우에만 삭제
          currentNode.removeChild(character);
        };
    
        // Start depth-first deletion from the head node.
        depthFirstDelete(this.head);
    
        return this;
      }
    
      suggestNextCharacters(word) {
        const lastCharacter = this.getLastCharacterNode(word);
    
        if (!lastCharacter) {
          return null;
        }
    
        return lastCharacter.suggestChildren();
      }
    
       // Check if complete word exists in Trie.
      doesWordExist(word) {
        const lastCharacter = this.getLastCharacterNode(word);
    
        return !!lastCharacter && lastCharacter.isCompleteWord;
      }
    
      getLastCharacterNode(word) {
        const characters = Array.from(word);
        let currentNode = this.head;
    
        for (let charIndex = 0; charIndex < characters.length; charIndex += 1) {
          if (!currentNode.hasChild(characters[charIndex])) {
            return null;
          }
    
          currentNode = currentNode.getChild(characters[charIndex]);
        }
    
        return currentNode;
      }
    }
    

    📚 リファレンス


    Github | tech-interview-for-developer
    Github | Interview_Question_for_Beginner
    Github | javascript-algorithms | trekhleb
    Photo by Alain Pham on Unsplash