527 Word Abbreviation
Problem:
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. 
Solutions:
public class Solution {
    public List<String> wordsAbbreviation(List<String> dict) {
        List<String> res = new ArrayList<String>();
        HashMap<String, List<Integer>> map = new HashMap<String, List<Integer>>();
        int i = 0;
        for (String s:dict) {
            if (s.length() <= 3) {
                res.add(s);
                i ++;
                continue;
            }            
            String tmp = s.charAt(0) + ((s.length() - 2) + "") + s.charAt(s.length() - 1);
            if (!map.containsKey(tmp)) {
                map.put(tmp, new LinkedList<Integer>());
            }
            map.get(tmp).add(i);
            res.add(tmp);
            i ++;
        }
        while (map.size() > 0) {
            HashMap<String, List<Integer>> newMap = new HashMap<String, List<Integer>>();
            List<String> toRemove = new LinkedList<String>();
            for (String key:map.keySet()) {
                List<Integer> indexes = map.get(key);
                if (indexes.size() == 1) {
                    toRemove.add(key);
                }
            }
            for (String key:toRemove) {
                map.remove(key);
            }
            for (String key:map.keySet()) {
                List<Integer> indexes = map.get(key);
                String prefix = findCommonPrefix(indexes, dict);
                for (Integer j:indexes) {
                    String original = dict.get(j);
                    if (original.length() - prefix.length() <=3) {
                        res.set(j, original);
                    }
                    else {
                        String replace = prefix + original.charAt(prefix.length()) + (original.length() - prefix.length() - 2) + original.charAt(original.length() - 1);
                        res.set(j, replace);
                        if (!newMap.containsKey(replace)) {
                            newMap.put(replace, new LinkedList<Integer>());
                        }
                        newMap.get(replace).add(j);
                    }
                }
            }
            map = newMap;
        }
        return res;
    }
    private String findCommonPrefix(List<Integer> indexes, List<String> dict) {
        String prefix = dict.get(indexes.get(0));
        for (int i = 1; i < indexes.size(); i ++) {
            int index = indexes.get(i);
            String compare = dict.get(index);
            for (int j = prefix.length(); j >= 0; j --) {
                if (prefix.substring(0, j).equals(compare.substring(0, j))) {
                    prefix = prefix.substring(0, j);
                    break;
                }
            }
        }
        return prefix;
    }
}Last updated