288. Unique Word Abbreviation

LeetCode medium original: C# #csharp #design #hash-table #leetcode #medium #string
Task text is translated from Russian for the selected interface language. Code is left unchanged.

Сокращение слова — это объединение его первой буквы, количества символов между первой и последней буквой и последней буквы. Если слово состоит только из двух символов, то оно является сокращением само по себе.

НаExample:

dog --> d1g, потому что между первой буквой 'd' и последней буквой 'g' одна буква.

internationalization --> i18n, потому что между первой буквой 'i' и последней буквой 'n' 18 букв.

it --> it, потому что любое слово из двух символов является своим собственным сокращением.

Реализуйте класс ValidWordAbbr:

ValidWordAbbr(String[] dictionary) Инициализирует объект со словарем слов.

boolean isUnique(string word) returns true, если выполняется одно из следующих условий (в противном случае returns false):

В словаре нет слова, сокращение которого равно сокращению слова word.

Для любого слова в словаре, сокращение которого равно сокращению слова word, это слово и word одинаковы.

Example:

Input

["ValidWordAbbr", "isUnique", "isUnique", "isUnique", "isUnique", "isUnique"]

[[["deer", "door", "cake", "card"]], ["dear"], ["cart"], ["cane"], ["make"], ["cake"]]

Output

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

Explanation

ValidWordAbbr validWordAbbr = new ValidWordAbbr(["deer", "door", "cake", "card"]);

validWordAbbr.isUnique("dear"); // return false, dictionary word "deer" and word "dear" have the same abbreviation "d2r" but are not the same.

validWordAbbr.isUnique("cart"); // return true, no words in the dictionary have the abbreviation "c2t".

validWordAbbr.isUnique("cane"); // return false, dictionary word "cake" and word "cane" have the same abbreviation "c2e" but are not the same.

validWordAbbr.isUnique("make"); // return true, no words in the dictionary have the abbreviation "m2e".

validWordAbbr.isUnique("cake"); // return true, because "cake" is already in the dictionary and no other word in the dictionary has "c2e" abbreviation.

C# solution

matched/original
public class ValidWordAbbr {
    private readonly Dictionary<string, bool> abbrDict = new Dictionary<string, bool>();
    private readonly HashSet<string> dict;
    public ValidWordAbbr(string[] dictionary) {
        dict = new HashSet<string>(dictionary);
        foreach (var word in dict) {
            var abbr = ToAbbr(word);
            abbrDict[abbr] = !abbrDict.ContainsKey(abbr);
        }
    }
    public bool IsUnique(string word) {
        var abbr = ToAbbr(word);
        return !abbrDict.ContainsKey(abbr) || (abbrDict[abbr] && dict.Contains(word));
    }
    private string ToAbbr(string word) {
        int n = word.Length;
        return n <= 2 ? word : $"{word[0]}{n - 2}{word[n - 1]}";
    }
}

C++ solution

auto-draft, review before submit
#include <bits/stdc++.h>
using namespace std;

// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
public class ValidWordAbbr {
    private readonly unordered_map<string, bool> abbrDict = new unordered_map<string, bool>();
    private readonly HashSet<string> dict;
    public ValidWordAbbr(vector<string> dictionary) {
        dict = new HashSet<string>(dictionary);
        foreach (var word in dict) {
            var abbr = ToAbbr(word);
            abbrDict[abbr] = !abbrDict.count(abbr);
        }
    }
    public bool IsUnique(string word) {
        var abbr = ToAbbr(word);
        return !abbrDict.count(abbr) || (abbrDict[abbr] && dict.Contains(word));
    }
    private string ToAbbr(string word) {
        int n = word.size();
        return n <= 2 ? word : $"{word[0]}{n - 2}{word[n - 1]}";
    }
}

Java solution

matched/original
public class ValidWordAbbr {
    private final Map<String, Boolean> abbrDict = new HashMap<>();
    private final Set<String> dict;

    public ValidWordAbbr(String[] dictionary) {
        dict = new HashSet<>(Arrays.asList(dictionary));
        for (String s : dict) {
            String abbr = toAbbr(s);
            abbrDict.put(abbr, !abbrDict.containsKey(abbr));
        }
    }

    public boolean isUnique(String word) {
        String abbr = toAbbr(word);
        Boolean hasAbbr = abbrDict.get(abbr);
        return hasAbbr == null || (hasAbbr && dict.contains(word));
    }

    private String toAbbr(String s) {
        int n = s.length();
        if (n <= 2) {
            return s;
        }
        return s.charAt(0) + Integer.toString(n - 2) + s.charAt(n - 1);
    }
}

JavaScript solution

matched/original
class ValidWordAbbr {
    constructor(dictionary) {
        this.abbrDict = new Map();
        this.dict = new Set(dictionary);
        for (const word of this.dict) {
            const abbr = this.toAbbr(word);
            this.abbrDict.set(abbr, !this.abbrDict.get(abbr));
        }
    }

    isUnique(word) {
        const abbr = this.toAbbr(word);
        const hasAbbr = this.abbrDict.get(abbr);
        return hasAbbr === undefined || (hasAbbr && this.dict.has(word));
    }

    toAbbr(word) {
        const n = word.length;
        if (n <= 2) {
            return word;
        }
        return `${word[0]}${n - 2}${word[n - 1]}`;
    }
}

Python solution

matched/original
class ValidWordAbbr:
    def __init__(self, dictionary: List[str]):
        self.abbr_dict = {}
        self.dict = set(dictionary)
        for word in self.dict:
            abbr = self.to_abbr(word)
            self.abbr_dict[abbr] = not self.abbr_dict.get(abbr, False)

    def isUnique(self, word: str) -> bool:
        abbr = self.to_abbr(word)
        has_abbr = self.abbr_dict.get(abbr)
        return has_abbr is None or (has_abbr and word in self.dict)

    def to_abbr(self, word: str) -> str:
        n = len(word)
        if n <= 2:
            return word
        return f"{word[0]}{n - 2}{word[-1]}"

Go solution

matched/original
type ValidWordAbbr struct {
    abbrDict map[string]bool
    dict     map[string]struct{}
}

func Constructor(dictionary []string) ValidWordAbbr {
    abbrDict := make(map[string]bool)
    dict := make(map[string]struct{})
    for _, word := range dictionary {
        dict[word] = struct{}{}
        abbr := toAbbr(word)
        abbrDict[abbr] = !abbrDict[abbr]
    }
    return ValidWordAbbr{abbrDict: abbrDict, dict: dict}
}

func (this *ValidWordAbbr) IsUnique(word string) bool {
    abbr := toAbbr(word)
    _, hasAbbr := this.abbrDict[abbr]
    _, inDict := this.dict[word]
    return !hasAbbr || (this.abbrDict[abbr] && inDict)
}

func toAbbr(word string) string {
    n := len(word)
    if n <= 2 {
        return word
    }
    return fmt.Sprintf("%c%d%c", word[0], n-2, word[n-1])
}

Algorithm

Инициализация:

Создайте словарь сокращений abbrDict, который будет хранить сокращения слов в виде ключей и булевы значения, указывающие, уникально ли сокращение.

Создайте множество dict, содержащее все слова из словаря, чтобы быстро проверять наличие слова в словаре.

Генерация сокращений:

При инициализации объекта ValidWordAbbr пройдите через каждое слово в словаре и создайте его сокращение.

Если сокращение уже существует в abbrDict, установите значение в false (не уникальное). В противном случае установите значение в true (уникальное).

Проверка уникальности:

Для метода isUnique создайте сокращение для Inputного слова и проверьте, есть ли это сокращение в abbrDict.

Если сокращение отсутствует в abbrDict, возвращайте true.

Если сокращение присутствует и оно уникально, проверьте, есть ли это слово в словаре. Если да, возвращайте true, в противном случае - false.

😎

Vacancies for this task

Active vacancies with overlapping task tags are shown.

All vacancies
There are no active vacancies yet.