题目:
Given an array of n distinct non-empty strings, you need to generate minimal possible abbreviations for every word following rules below.
- Begin with the first character and then the number of characters abbreviated, which followed by the last character.
- If there are any conflict, that is more than one words share the same abbreviation, a longer prefix is used instead of only the first character until making the map from word to abbreviation become unique. In other words, a final abbreviation cannot map to more than one original words.
- If the abbreviation doesn't make the word shorter, then keep it as original.
Example:
Input: ["like", "god", "internal", "me", "internet", "interval", "intension", "face", "intrusion"] Output: ["l2e","god","internal","me","i6t","interval","inte4n","f2e","intr4n"]
Note:
- Both n and the length of each word will not exceed 400.
- The length of each word is greater than 1.
- The words consist of lowercase English letters only.
- The return answers should be in the same order as the original array.
思路:
注意到这样一个事实:凡是有可能发生缩写冲突的单词,必然满足如下两个条件:1)长度相同;2)有相同的前缀。所以我们可以首先对字典中的单词按照长度以及单词本身的字典序进行排序。对于排序后的字典中的每个单词,分别计算它和前面一个单词以及后面一个单词的共同前缀的长度,并取最大值。这个最大值+1其实就是该单词在缩略过程中需要保持原貌的部分的长度。然后判断缩略后长度是否会缩小,如果是,则对该单词进行缩略,否则保持原貌。处理完成之后,恢复单词在原来字典中的顺序即可。
算法的时间复杂度是O(nlogn),空间复杂度是O(n)。
代码:
class Solution {
public:
vector<string> wordsAbbreviation(vector<string>& dict) {
vector<pair<string, int>> d; // {string, index}
for (int i = 0; i < dict.size(); ++i) {
d.push_back(make_pair(dict[i], i));
}
sort(d.begin(), d.end(), PairComp);
vector<int> pre_common(d.size(), 0), post_common(d.size(), 0);
for (int i = 1; i < d.size(); ++i) {
pre_common[i] = commonLength(d[i-1].first, d[i].first);
}
for (int i = 0; i + 1 < d.size(); ++i) {
post_common[i] = commonLength(d[i].first, d[i + 1].first);
}
vector<string> ret(dict.size(), "");
for (int i = 0; i < d.size(); ++i) {
int least_common = max(pre_common[i], post_common[i]);
if (least_common + 3 < d[i].first.length()) {
d[i].first = d[i].first.substr(0, least_common + 1) +
to_string(d[i].first.length() - least_common - 2) + d[i].first.back();
}
ret[d[i].second] = d[i].first;
}
return ret;
}
private:
struct PairCompare {
bool operator() (const pair<string, int> &a, const pair<string, int> &b) const {
const string &s1 = a.first;
const string &s2 = b.first;
if (s1.length() == s2.length()) {
if (s1.back() == s2.back()) {
return s1 < s2;
}
else {
return s1.back() < s2.back();
}
}
else {
return s1.length() < s2.length();
}
}
} PairComp;
int commonLength(const string &s1, const string &s2) const {
if (s1.length() != s2.length() || s1.back() != s2.back()) {
return 0;
}
else {
for (int i = 0; i < s1.length(); ++i) {
if (s1[i] != s2[i]) {
return i;
}
}
return s1.length();
}
}
};