Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

codingfarm

966. Vowel Spellchecker 본문

Algorithm & Data structure/Problem Solution

966. Vowel Spellchecker

scarecrow1992 2019. 12. 6. 00:24

https://leetcode.com/problems/vowel-spellchecker/

 

Vowel Spellchecker - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

 

Given a wordlist, we want to implement a spellchecker that converts a query word into a correct word.

For a given query word, the spell checker handles two categories of spelling mistakes:

  • Capitalization: If the query matches a word in the wordlist (case-insensitive), then the query word is returned with the same case as the case in the wordlist.
    • Example: wordlist = ["yellow"], query = "YellOw": correct = "yellow"
    • Example: wordlist = ["Yellow"], query = "yellow": correct = "Yellow"
    • Example: wordlist = ["yellow"], query = "yellow": correct = "yellow"
  • Vowel Errors: If after replacing the vowels ('a', 'e', 'i', 'o', 'u') of the query word with any vowel individually, it matches a word in the wordlist (case-insensitive), then the query word is returned with the same case as the match in the wordlist.
    • Example: wordlist = ["YellOw"], query = "yollow": correct = "YellOw"
    • Example: wordlist = ["YellOw"], query = "yeellow": correct = "" (no match)
    • Example: wordlist = ["YellOw"], query = "yllw": correct = "" (no match)

In addition, the spell checker operates under the following precedence rules:

  • When the query exactly matches a word in the wordlist (case-sensitive), you should return the same word back.
  • When the query matches a word up to capitlization, you should return the first such match in the wordlist.
  • When the query matches a word up to vowel errors, you should return the first such match in the wordlist.
  • If the query has no matches in the wordlist, you should return the empty string.

Given some queries, return a list of words answer, where answer[i] is the correct word for query = queries[i].

 

Example 1:

Input: wordlist = ["KiTe","kite","hare","Hare"], queries = ["kite","Kite","KiTe","Hare","HARE","Hear","hear","keti","keet","keto"] Output: ["kite","KiTe","KiTe","Hare","hare","","","KiTe","","KiTe"]

 

Note:

  • 1 <= wordlist.length <= 5000
  • 1 <= queries.length <= 5000
  • 1 <= wordlist[i].length <= 7
  • 1 <= queries[i].length <= 7
  • All strings in wordlist and queries consist only of english letters.

 

 


문제가 굉장히 까다롭고 해석도 어렵다.

 

결론적으로 말하면 queries에서 받은 문자열을 wordlist로 대체 가능하냐는것이다.

 

대체의 기준은

  1. 모든 대문자를 소문자로 변경한 결과가 wordlist에 있는가
  2. a, e, i, o, u 5개의 문자를 서로간에 변경이 가능할때에 wordlist에 있는가

풀이방법은 도무지 감이 안잡혔지만 topic에 hash table을 써라는 것을 보고 힌트를 얻었다.

 

queries에 있는 문자열와 호환이 가능한 문자열을 key로 삼아 해쉬에서 탐색하면 되는것이다.

 

가령

wordlist 에 yellow 가 있고 queries에 YellOw가 있으면 쿼리의 문자열을 소문자로 바꾼 yellow를 통해 검색한 결과를 얻을 수 있다.

 

그리고

wordlist 에 ae 가 있고 queries에 UU가 있으면 쿼리의 문자열을 소문자로 바꾼 ae를 통해 검색한 결과를 얻을 수 있다.

 

 

그러기 위해선 우리는 3가지 해쉬를 만들어야 한다.

org : wordlist의 문자열을 있는 그대로 key삼아 검색하는 hash

cap : wordlist의 문자열에서 대문자를 소문자로 바꾼 문자열을 key 삼아 검색하는 hash

vowel : wordlist의 문자열에서 a, e, i, o, u를 #으로 바꾼 문자열을 key 삼아 검색하는 hash

 

3가지 해쉬를 모두다 정의 해준 후엔

 

queries에 있는 문자열 또한 필요에 따라 규칙에 맞게 변형 시켜서 3가지 hash에서 검색하도록 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#include<iostream>
#include<string>
#include<vector>
 
using namespace std;
 
string dummy = "";
 
class HashListNode {
public:
    string value;
    string key;
    HashListNode *pPrev, *pNext;
 
    HashListNode() {
        value = -1;
        pPrev = 0;
        pNext = 0;
    }
};
 
 
HashListNode hashListNodePool[500000];
int hashListNodePoolIndex;
 
void HashListNodePoolInit() {
    hashListNodePoolIndex = 0;
}
 
 
HashListNode* NewHashListNode() {
    HashListNode* newNode;
    newNode = &hashListNodePool[hashListNodePoolIndex];
    hashListNodePoolIndex++;
 
    newNode->pNext = 0;
    newNode->pPrev = 0;
    return newNode;
}
 
 
class HashList {
public:
    int cnt;
    HashListNode *front*back;
 
    void Init() {
        cnt = 0;
        front = NewHashListNode();
        back = NewHashListNode();
 
        front->pNext = back;
        back->pPrev = front;
    }
 
 
 
    void PushBack(string &value, string &key) {
        HashListNode *newNode = NewHashListNode();
        newNode->value = value;
        newNode->key = key;
 
 
        HashListNode *lastNode = back->pPrev;
        lastNode->pNext = newNode;
        back->pPrev = newNode;
 
        newNode->pPrev = lastNode;
        newNode->pNext = back;
        cnt++;
    }
 
 
    bool Insert(string &newValue, string &newKey) {
        //중복 여부 조사    
        PushBack(newValue, newKey);
 
        return true;
    }
 
 
    HashListNode* Erase(HashListNode *deleteNode) {
        HashListNode *prevNode = deleteNode->pPrev;
        HashListNode *nextNode = deleteNode->pNext;
 
        prevNode->pNext = nextNode;
        nextNode->pPrev = prevNode;
 
        delete deleteNode;
        cnt--;
 
        return nextNode;
    }
 
    string& Find(string &key) {
        HashListNode *it = front->pNext;
 
        for (it = front->pNext; it != back; it = it->pNext) {
            if (it->key == key)
                break;
        }
 
        if (it != back)
            return it->value;
        else
            return dummy;
    }
};
 
 
class Hash {
public:
    int cnt;
    HashList hashTable[5017];
 
    void Init() {
        cnt = 0;
 
        for (int i = 0; i < 5017; i++)
            hashTable[i].Init();
    }
 
    int HashFunction(string &key) {
 
        char c;
        int ret = 0;
        for (int i = 0; i < key.size(); i++) {
            c = key[i];
 
            //ret = ((ret * 31) + c - 'a') % 1000;
            if(c >= 'a' && c <= 'z')
                ret = ((ret * 31+ c - 'a') % 5017;
            else if(c >= 'A' && c <= 'Z')
                ret = ((ret * 31+ c - 'A') % 5017;
            else if(c == '#')
                ret = ((ret * 31+ 31) % 5017;
 
        }
        return ret;
    }
 
 
    string Find(string &key) {
        int address = HashFunction(key);
 
        string &ret = hashTable[address].Find(key);
 
        return ret;
    }
 
    bool Insert(string &key, string &value) {
        //이미있는지 점검과 삽입을 동시에 한다
        //삽입 도중에 이미 있음이 발견되면 바로 false 반환
 
        int address = HashFunction(key);
 
        bool ret = hashTable[address].Insert(value, key);
        return ret;
    }
 
};
 
 
string ToLower(string &str) {
    string ret;
    int diff = 'A' - 'a';
 
    for (int i = 0; i < str.size(); i++) {
        if (str[i] >= 'A' && str[i] <= 'Z')
            ret.push_back(str[i] - diff);
        else
            ret.push_back(str[i]);
    }
    return ret;
}
 
string ToVowel(string &str) {
    string ret;
 
    for (int i = 0; i < str.size(); i++) {
        if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o' || str[i] == 'u')
            ret.push_back('#');
        else
            ret.push_back(str[i]);
    }
 
    return ret;
}
 
 
class Solution {
public:
    vector<string> spellchecker(vector<string>& wordlist, vector<string>& queries) {
        Hash org, cap, vowel;
        string tmp;
 
        HashListNodePoolInit();
        org.Init(); cap.Init(); vowel.Init();
 
        //cap에 wordlist 내의 값들을 모두다 집어 넣는다
        //key는 모든 문자열을 소문자로 바꾼 값이다.
 
        //vowel에 queries 내의 문자열을 모두 넣는다
        //key는 a, e, i ,o ,u 를 #으로 바꾼 문자열이다.
        for (int i = 0; i < wordlist.size(); i++) {
            org.Insert(wordlist[i], wordlist[i]);
 
            tmp = ToLower(wordlist[i]);
            cap.Insert(tmp, wordlist[i]);
 
            tmp = ToVowel(tmp);
            vowel.Insert(tmp, wordlist[i]);
        }
 
        string ret, key;
        //이제 queries의 값을 변환 가능한지 점검한다.
        for (int i = 0; i < queries.size(); i++) {
            //아무것도 바꿀 필요가 없을 경우
            ret = org.Find(queries[i]);
 
            if (ret != dummy)
                continue;
 
            //소문자로 바꾼 결과가 cap에 있을 경우
            key = ToLower(queries[i]);
            ret = cap.Find(key);
 
            if (ret != dummy) {
                queries[i] = ret;
                continue;
            }
 
            //a,e,i,o,u 로 바꾼 결과가 vowel에 있을 경우
            key = ToVowel(key);
            ret = vowel.Find(key);
 
            if (ret != dummy) {
                queries[i] = ret;
                continue;
            }
 
            //아무것도 해당사항이 없으면 문자열을 비운다.
            queries[i] = "";
        }
 
        return queries;
    }
};
 
 
 
int main(void) {
    int N, M;
    cin >> N >> M;
 
    string str;
    vector<string> wordlist, queries;
 
 
    for (int i = 0; i < N; i++) {
        cin >> str;
        wordlist.push_back(str);
    }
 
    for (int i = 0; i < M; i++) {
        cin >> str;
        queries.push_back(str);
    }
 
    Solution sol;
    vector<string> ret = sol.spellchecker(wordlist, queries);
 
    for (int i = 0; i < ret.size(); i++) {
        cout << ret[i] << endl;
    }
 
    return 0;
}
cs

 

 

 

 

 

 

 

 

 

 

 

 

Comments