​LeetCode刷题实战527:单词缩写

算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !

今天和大家聊的问题叫做 单词缩写,我们先来看题面:

https://leetcode-cn.com/problems/word-abbreviation/

Given an array of n distinct non-empty strings, you need to generate minimal possible abbreviations for every word following rules below.

  1. Begin with the first character and then the number of characters abbreviated, which followed by the last character.

  2. 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.

  3. If the abbreviation doesn't make the word shorter, then keep it as original.

给定一个由n个不重复非空字符串组成的数组,你需要按照以下规则为每个单词生成最小的缩写。

  • 初始缩写由起始字母+省略字母的数量+结尾字母组成。

  • 若存在冲突,亦即多于一个单词有同样的缩写,则使用更长的前缀代替首字母,直到从单词到缩写的映射唯一。换而言之,最终的缩写必须只能映射到一个单词。

  • 若缩写并不比原单词更短,则保留原样。

示例                         

示例:
输入: ["like", "god", "internal", "me", "internet", "interval", "intension", "face", "intrusion"]
输出: ["l2e","god","internal","me","i6t","interval","inte4n","f2e","intr4n"]
 
注意:
n和每个单词的长度均不超过 400。
每个单词的长度大于 1。
单词只由英文小写字母组成。
返回的答案需要和原数组保持同一顺序。

解题

https://blog.csdn.net/weixin_43708069/article/details/108202105

看到题目第一眼就感觉是要用字典树了,但是奈何我忘了,只记得大概的思想,然后补习了一遍,参考了题解的一些做法做出来了= =

大概思路:

  • 先把每个单词根据它们的缩写进行分组,同时再用一个map记录每个单词在原单词表中的位置

  • 对分好组的单词插入字典树

  • 通过字典树的前缀,判断单词的缩写形式(详情见下面代码)

// 字典树类
class Trie{
public:
    Trie* next[26] = {NULL}; //字典树的26个字数,代表26的字母'a'-'z'
    int cnt = 0; //拥有该前缀的单词数量
    void insert(string& s){ //字典树的插入函数,用于在字典树中插入单词s
        Trie* t = this;

        for(int i=0; i<s.size(); i++){
            if(t->next[s[i]-'a'] == NULL) //若节点不存在,则创建节点
                t->next[s[i]-'a'] = new Trie();
            t = t->next[s[i]-'a'];
            t->cnt++; //拥有该前缀的单词数量+1
        }
    } 
};

class Solution {
public:
    vector<string> wordsAbbreviation(vector<string>& dict) {
        int n = dict.size(); //单词数量
        unordered_map<string, vector<string>> group; //分组所用容器
        unordered_map<string, int> pos; //记录原始单词表dict每个单词的位置
        vector<string> ans(n); //存储单词列表缩写

        for(int i=0; i<n; i++){ //分组操作
            int m = dict[i].size(); //每个单词的长度
            string tmp = dict[i][0] + to_string(m) + dict[i][m-1]; //每个单词的缩写
            group[tmp].push_back(dict[i]); //根据每个单词缩写进行分组
            pos[dict[i]] = i; //记录原始单词列表dict每个单词的原始位置
        }

        unordered_map<string, vector<string>>::iterator it; //迭代器
        for(it=group.begin(); it!=group.end(); it++){ //遍历group it->first对应每个缩写 it->second对应该缩写下的所有单词
            vector<string> strs = it->second; //获取该缩写下所有单词
            int m = strs.size(); //该缩写下所有单词数量
            Trie *p = new Trie(), *q; //建立字典树

            for(int i=0; i<m ;i++)
                p->insert(strs[i]); //将单词插入字典树

            for(int i=0; i<m; i++){
                q = p;
                string tmp; //记录单词的缩写形式

                //根据字典树前缀判断单词缩写形式
                for(int j=0; j<strs[i].size(); j++){
                    //若该前缀下单词只有一个
                    if(q->next[strs[i][j]-'a']->cnt==1){
                        //可缩写的字符数量
                        int k = strs[i].size()-j-2;

                        //若可缩写的字符数量大于1,则进行缩写,否则保持单词原型不变
                        if(k>1)
                            tmp += strs[i][j] + to_string(k) + strs[i][strs[i].size()-1];
                        else
                            tmp = strs[i];

                        break;
                    }
                    
                    tmp += strs[i][j]; //单词前缀增加
                    q = q->next[strs[i][j]-'a']; 
                }
                ans[pos[strs[i]]] = tmp; //根据pos中每个单词的原始位置,存放单词的缩写形式
            }
        }

        return ans;
    }
};

好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力 。

上期推文:

LeetCode1-520题汇总,希望对你有点帮助!

LeetCode刷题实战521:最长特殊序列 Ⅰ

LeetCode刷题实战522:最长特殊序列 II

LeetCode刷题实战523:连续的子数组和

LeetCode刷题实战524:通过删除字母匹配到字典里最长单词

LeetCode刷题实战525:连续数组

LeetCode刷题实战526:优美的排列

7d78a55df7b82adbeee6fbf73ed6fa51.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值