leetcode527 - Word Abbreviation - hard

Posted jasminemzy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode527 - Word Abbreviation - hard相关的知识,希望对你有一定的参考价值。

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.
Example:
Input: ["like", "god", "internal", "me", "internet", "interval", "intension", "face", "intrusion"]
Output: ["l2e","god","internal","me","i6t","interval","inte4n","f2e","intr4n"]
Note:
1. Both n and the length of each word will not exceed 400.
2. The length of each word is greater than 1.
3. The words consist of lowercase English letters only.
4. The return answers should be in the same order as the original array.
 
模拟法。Map辅助。
写一个子方法,能根据需求的prefix长度来把s做转换后传回。
 
法1.用Map<String, Integer>存储每个abbr当前有出现过几次,提供查询。具体的每个下标当前的缩进结果放在ans数组里,当前缩进几格放在prefix数组里。每轮检查当前result[i]合格了没,要是返回的count>1那就是不合格的,得增大prefix继续更新。要是某轮后没有任何更新就跳出循环。
细节
1.每轮更新放大prefix做更新后不要降级老string的计数。解释:intension和intrusion最后转化成的是inte4n和intr4n,而不是inte4n和int3n,是不是奇怪这两个已经不一样了为什么不让一个进一步呢?因为题目有说a final abbreviation cannot map to more than one original words,而int3n同时map到那两个字符串了不行的。如果你代码里让老string的计数降级,那你可能遍历到intr4n的时候就发现int3n的count已经变成1了,对字符串intrusion它就不做从int3n到intr4n的转变了,那就错了。
2.题目说的少缩进一些的方法不是每次均匀往中间少缩两格放出两个字母,只是prefix缩一格进去,非对称。
3.存放中间结果和每个string当前prefix长度用的array而不是list,因为list不能在长度还未到达的时候set某一个后面的位置。
4.array -> list的API:Collections.addAll(list, array)。
 
法2. 用Map<String, List<Integer>>存储每个缩写一定程度后的abbr对应的初始字符的下标。当map的大小和输入list一致,就说明每个abbr都是独立的了,达成目标。如果还没有成功的话,就从那些不合格的entry取到初始字符,再进一步留多一些prefix。
细节:每次要开新map: 你不能在遍历keySet()的时候又给keySet()插入删除key值,这是逻辑不对而且编译会报错ConcurrentModificationException。 

 

实现1:

class Solution {
    public List<String> wordsAbbreviation(List<String> dict) {
        if (dict == null || dict.size() == 0) {
            return new ArrayList<String>();
        }
        
        int[] prefix = new int[dict.size()];
        String[] result = new String[dict.size()];
        Map<String, Integer> count = new HashMap<>();
        
        // initialization
        for (int i = 0; i < dict.size(); i++) {
            prefix[i]++;
            String abbr = abbreviate(dict.get(i), prefix[i]);
            result[i] = abbr;
            count.put(abbr, count.getOrDefault(abbr, 0) + 1);
        }
        
        boolean hasDup = true;
        while (hasDup) {
            hasDup = false;
            for (int i = 0; i < dict.size(); i++) {
                if (count.get(result[i]) > 1) {
                    hasDup = true;
                    prefix[i]++;
                    String newAbbr = abbreviate(dict.get(i), prefix[i]);
                    result[i] = newAbbr;
                    count.put(newAbbr, count.getOrDefault(newAbbr, 0) + 1);
                }
            }
        }
        
        // P3: 生成List
        List<String> resultList = new ArrayList<>();
        Collections.addAll(resultList, result);
        return resultList;
    }
    
    private String abbreviate(String s, int prefix) {
        if (s.length() - prefix - 1 <= 1) {
            return s;
        } else {
            // P2: 注意题意不是每次均匀往中间缩两格,只是prefix缩一格进去。
            return s.substring(0, prefix) + (s.length() - prefix - 1) + s.substring(s.length() - 1, s.length());
        }
    }
}

 

 

实现2:

class Solution {
    public List<String> wordsAbbreviation(List<String> dict) {
        if (dict == null || dict.size() == 0) {
            return new ArrayList<String>();
        }
        
        Map<String, List<Integer>> strIdxes = new HashMap<>();
        int prefix = 1;
        
        // initialization
        for (int i = 0; i < dict.size(); i++) {
            String abbreved = abbreviate(dict.get(i), prefix);
            strIdxes.putIfAbsent(abbreved, new ArrayList<>());
            strIdxes.get(abbreved).add(i);
        }
        
        while (strIdxes.size() < dict.size()) {
            prefix++;
            System.out.println(prefix);
            // P1: 每次要开新map的原因: 你不能在遍历keySet()的时候又给keySet()插入删除key值,这是逻辑不对而且编译会报错ConcurrentModificationException。
            Map<String, List<Integer>> newMap = new HashMap<>();
            for (String s : strIdxes.keySet()) {
                List<Integer> indexes = strIdxes.get(s);
                if (indexes.size() == 1) {
                    newMap.put(s, indexes);
                    continue;
                }
                for (int index : indexes) {
                    String newAbbreved = abbreviate(dict.get(index), prefix);
                    newMap.putIfAbsent(newAbbreved, new ArrayList<>());
                    newMap.get(newAbbreved).add(index);
                }
            }
            strIdxes = newMap;
        }
        
        // P3: 生成List
        String[] resultArr = new String[dict.size()];
        for (String s : strIdxes.keySet()) {
            resultArr[strIdxes.get(s).get(0)] = s;
        }
        List<String> result = new ArrayList<>();
        Collections.addAll(result, resultArr);
        return result;
    }
    
    private String abbreviate(String s, int prefix) {
        if (s.length() - prefix - 1 <= 1) {
            return s;
        } else {
            // P2: 注意题意不是每次均匀往中间缩两格,只是prefix缩一格进去。
            return s.substring(0, prefix) + (s.length() - prefix - 1) + s.substring(s.length() - 1, s.length());
        }
    }
}

 

以上是关于leetcode527 - Word Abbreviation - hard的主要内容,如果未能解决你的问题,请参考以下文章

[LeetCode] 527. Word Abbreviation 单词缩写

错误:EPERM:不允许操作,取消链接 'D:\Sources\**\node_modules\fsevents\node_modules\abbrev\package.json'

[LeetCode]Word Search

LeetCode Unique Word Abbreviation

leetcode笔记:Maximum Product of Word Lengths

leetcode笔记:Word Pattern