• [LeetCode]642. Design Search Autocomplete System(JavaScript解法)


    题目描述

    LeetCode原题链接:642. Design Search Autocomplete System

    Design a search autocomplete system for a search engine. Users may input a sentence (at least one word and end with a special character '#').

    You are given a string array sentences and an integer array times both of length n where sentences[i] is a previously typed sentence and times[i] is the corresponding number of times the sentence was typed. For each input character except '#', return the top 3 historical hot sentences that have the same prefix as the part of the sentence already typed.

    Here are the specific rules:

    • The hot degree for a sentence is defined as the number of times a user typed the exactly same sentence before.
    • The returned top 3 hot sentences should be sorted by hot degree (The first is the hottest one). If several sentences have the same hot degree, use ASCII-code order (smaller one appears first).
    • If less than 3 hot sentences exist, return as many as you can.
    • When the input is a special character, it means the sentence ends, and in this case, you need to return an empty list.

    Implement the AutocompleteSystem class:

    • AutocompleteSystem(String[] sentences, int[] times) Initializes the object with the sentences and times arrays.
    • List<String> input(char c) This indicates that the user typed the character c.
      • Returns an empty array [] if c == '#' and stores the inputted sentence in the system.
      • Returns the top 3 historical hot sentences that have the same prefix as the part of the sentence already typed. If there are fewer than 3 matches, return them all.

    Example 1:

    Input
    ["AutocompleteSystem", "input", "input", "input", "input"]
    [[["i love you", "island", "iroman", "i love leetcode"], [5, 3, 2, 2]], ["i"], [" "], ["a"], ["#"]]
    Output
    [null, ["i love you", "island", "i love leetcode"], ["i love you", "i love leetcode"], [], []]
    
    Explanation
    AutocompleteSystem obj = new AutocompleteSystem(["i love you", "island", "iroman", "i love leetcode"], [5, 3, 2, 2]);
    obj.input("i"); // return ["i love you", "island", "i love leetcode"]. There are four sentences that have prefix "i". Among them, "ironman" and "i love leetcode" have same hot degree. Since ' ' has ASCII code 32 and 'r' has ASCII code 114, "i love leetcode" should be in front of "ironman". Also we only need to output top 3 hot sentences, so "ironman" will be ignored.
    obj.input(" "); // return ["i love you", "i love leetcode"]. There are only two sentences that have prefix "i ".
    obj.input("a"); // return []. There are no sentences that have prefix "i a".
    obj.input("#"); // return []. The user finished the input, the sentence "i a" should be saved as a historical sentence in system. And the following input will be counted as a new search.
    

     Constraints:

    • n == sentences.length
    • n == times.length
    • 1 <= n <= 100
    • 1 <= sentences[i].length <= 100
    • 1 <= times[i] <= 50
    • c is a lowercase English letter, a hash '#', or space ' '.
    • Each tested sentence will be a sequence of characters c that end with the character '#'.
    • Each tested sentence will have a length in the range [1, 200].
    • The words in each input sentence are separated by single spaces.
    • At most 5000 calls will be made to input.

    思路分析

    搜索自动补全设计题。

    在AutocompleteSystem类中,我们需要 1: 存储历史搜索记录和其对映热度的映射;2: 用户输入#号前所有输入内容的记录;3. 所有符合匹配和排序规则的候选句子优先级队列 这3个变量来完成自动补全的逻辑。可以用Map和Array来实现这些数据结构。

    • historySearch - 初始值来自构造函数的入参sentences,以句子为key,热度为value存入map中;当用户输入完一个完整句子(输入“#”后)时进行更新;
    • inputData - 初始值为[],调用AutocompleteSystem.input时更新;
    • queue - 初始值为[],储存<句子,热度>,始终保证热度高的句子排在队首;若有多个热度相同的句子,ASCII码小的排在前面。

    数据结构定义好之后,再来看用户input操作时需要实现的逻辑:

    1. 若用户输入“#”,表明一个完整句子结束。此时:
      • 更新historySearch:inputData出现过的话就times+1,没有出现过就新加入到map中;
      • 清空inputData和queue;
      • 输出空数组[]。

        2. 若用户输入非“#”号:

      • 第一个输入的字符:在historySearch中搜索匹配输入字母的句子,用这些匹配的句子初始化优先级队列queue
      • 非第一个输入的字符:根据新输入的字母,用新生成的inputData去移除queue不匹配的项
      • 输出queue的前三项;若queue.length < 3,有几项输出几项。

    这里需要再另外写两个工具类,首先是优先级队列的插入操作。因为js中没有priority_queue或是heap数据结构,所以这里用数组+二分法+插入排序来实现这个功能。先根据热度大小进行排序,找到从左到右数第一个 <= 要插入的句子的热度的数组下标index。如果index处的句子热度和要插入的句子热度相等,再比较ASCII码。

    另一个是检查输入的字符串和句子是否匹配。可以用正则表达式+字符串test方法,也可以直接for循环一位一位比较,有一位不匹配就break返回false。(两种代码提交后发现for循环进行匹配runtime更短)

    代码示例(Js)

    这道题思路比较清晰,相对而言不是很复杂。不过网上没大看到js解法的solution,所以这里用js写一下代码示例:

     1 /**
     2  * @param {string[]} sentences
     3  * @param {number[]} times
     4  */
     5 var AutocompleteSystem = function(sentences, times) {
     6     this.historySearch = new Map(); // 历史搜索内容&热度 映射表
     7     sentences.forEach((sentence, index) => {
     8         this.historySearch.set(sentence, times[index]);
     9     });
    10     this.inputData = []; // 用户输入的字符串
    11     this.queue = []; // 优先级队列
    12 };
    13 
    14 /** 
    15  * @param {character} c
    16  * @return {string[]}
    17  */
    18 AutocompleteSystem.prototype.input = function(c) {
    19     if(c == '#') {
    20         // 更新搜索历史
    21         let finalSentence = this.inputData.join('');
    22         let times = this.historySearch.has(finalSentence) ? this.historySearch.get(finalSentence) : 0;
    23         this.historySearch.set(finalSentence, times + 1);
    24         
    25         this.inputData = [];
    26         this.queue = [];
    27         return [];
    28     }
    29     if(this.inputData.length == 0) {
    30         for(let [sentence, times] of this.historySearch) {
    31             if(this.isMatch(sentence, c)) {
    32                 this.updateQueue([sentence, times]);
    33             }
    34         }
    35         this.inputData.push(c);
    36     }
    37     else {   
    38         this.inputData.push(c);
    39         this.queue = this.queue.filter((item) => this.isMatch(item[0], this.inputData.join('')));
    40     }
    41     let result = [];
    42     for(let i = 0; i < this.queue.length; i++) {
    43         result.push(this.queue[i][0]);
    44         if(result.length == 3) break;
    45     }
    46     return result;
    47 };
    48 
    49 // 向优先级队列中插入新的元素(binary search + 插入排序)
    50 AutocompleteSystem.prototype.updateQueue = function(pair) {
    51     let left = 0, right = this.queue.length;
    52     while(left < right) {
    53         let middle = Math.floor((left + right) / 2);
    54         // 用热度进行比较
    55         if(this.queue[middle][1] > pair[1]) {
    56             left = middle + 1;
    57         }
    58         else {
    59             right = middle;
    60         }
    61     }
    62     // 热度相同根据ASCII码进行比较
    63     while(right < this.queue.length && this.queue[right][1] == pair[1]) {
    64         if(pair[0] < this.queue[right][0]) break;
    65         right++;
    66     }
    67     this.queue.splice(right, 0, pair);
    68 };
    69 
    70 // 判断input是否和当前sentence匹配
    71 AutocompleteSystem.prototype.isMatch = function(sentence, prefix) {
    72     // let expression = new RegExp("^" + prefix);
    73     // return expression.test(sentence);
    74     for(let i = 0; i < prefix.length; i++) {
    75         if(prefix[i] != sentence[i]) return false;
    76     }
    77     return true;
    78 };
    79 
    80 /** 
    81  * Your AutocompleteSystem object will be instantiated and called as such:
    82  * var obj = new AutocompleteSystem(sentences, times)
    83  * var param_1 = obj.input(c)
    84  */
  • 相关阅读:
    JS新API标准 地理定位(navigator.geolocation
    微信公众号菜单
    js选择权
    mui 弹框
    又拍云
    弹框
    sublime插件
    将Apache的.htaccess转换到nginx中
    php 图片上传类
    C# 使用Com组件正确的释放方法
  • 原文地址:https://www.cnblogs.com/barryyeee/p/15358708.html
Copyright © 2020-2023  润新知