【leetcode】527. 单词缩写(贪心算法:先生成初识缩写,然后查找有冲突的组合,不断加长前缀直到没有冲突)

题目

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

  • 初始缩写由起始字母+省略字母的数量+结尾字幕组成。
  • 若存在冲突,亦即多于一个单词有同样的缩写,则使用更长的前缀代替首字母,直到从单词到缩写的映射唯一。换而言之,最终的缩写必须只能映射到一个单词。
  • 若缩写并不比原单词更短,则保留原样。

示例
输入:[“like”, “god”, “internal”, “me”, “internet”, “interval”, “intension”, “face”, “intrusion”]
输出: [“l2e”,“god”,“internal”,“me”,“i6t”,“interval”,“inte4n”,“f2e”,“intr4n”]

注意:

  • n和每个单词的长度均不超过 400。
  • 每个单词的长度大于 1。
  • 单词只由英文小写字母组成。
  • 返回的答案需要和原数组保持同一顺序。

贪心算法

首先给每个单词选择最短的缩写。然后我们对于所有重复的单词,我们增加这些重复项的长度。

比方说,我们有 “aabaaa”, “aacaaa”, “aacdaa”,我们首先得到 “a4a”, “a4a”, “a4a”。由于有重复项,我们将它们延长为 “aa3a”, “aa3a”, “aa3a”。此时仍然有重复项,所以我们继续延伸长度为 “aab2a”, “aac2a”, “aac2a”。最后两个字符串仍然是重复项,我们将它们继续延长得到 “aacaaa”, “aacdaa”。在此过程中,注意记录每个字符串解决冲突时前缀的长度,每次加加。

class Solution {
public:
    string abbreviate(string word, int lenOfPre){
        string suoxie = word.substr(0, lenOfPre); // 前缀
        int len = word.length() - lenOfPre;
        if( len <= 3 ){
            suoxie += word.substr(lenOfPre);
        }else{
            suoxie += word[lenOfPre] + to_string(len-2) + word[word.length()-1]; // 注意数字与字符串的转换
        }
        // cout << suoxie << endl;
        return suoxie;
    }
    vector<string> wordsAbbreviation(vector<string>& dict) {
        int size = dict.size();
        //先遍历一次,得初始缩写
        vector<string> result;
        for(int i=0; i<size; i++){
            result.push_back(abbreviate(dict[i],0));
        }
        for(int i=0; i<size; i++){
            //贪心:对于每个单词,查找并记录后面跟自己有冲突的,然后全部用更长的前缀代替。一直循环,直到没有冲突。
            int lenOfPre = 1; // 使用更长的前缀代替
            while(true){
                vector<int> recordIndex; // 记录有冲突的单词的下标
                for(int j=i+1; j<size; j++){
                    if( result[i] == result[j] ){
                        recordIndex.push_back(j); // 记录后面跟自己有冲突的
                    }
                }
                if(recordIndex.size()==0){
                    break;
                }else{
                    recordIndex.push_back(i); // 别漏掉当前单词自己
                    for( int k=0; k<recordIndex.size(); k++ ){
                        int index = recordIndex[k];
                        result[index] = abbreviate(dict[index], lenOfPre);
                    }
                    lenOfPre++;
                }
            }
        }
        return result;
    }
};

复杂度分析

  • 时间复杂度:O( C^2 )。其中 C 是给定数组中所有字符串的字符总数目。
  • 空间复杂度:O( C )。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值