527. 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.
Example:

Input: ["like", "god", "internal", "me", "internet", "interval", "intension", "face", "intrusion"]
Output: ["l2e","god","internal","me","i6t","interval","inte4n","f2e","intr4n"]



https://www.youtube.com/watch?v=yAQMcGY4c90&t=22s




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



Solution 1 : greedy 

Intuition
Let's choose the shortest abbreviation for each word. Then, while we have duplicates, we'll increase the length of all duplicates.
Algorithm
For example, let's say we have "aabaaa", "aacaaa", "aacdaa", then we start with "a4a", "a4a", "a4a". Since these are duplicated, we lengthen them to "aa3a", "aa3a", "aa3a". They are still duplicated, so we lengthen them to "aab2a", "aac2a", "aac2a". The last two are still duplicated, so we lengthen them to "aacaaa", "aacdaa".
Throughout this process, we were tracking an index prefix[i] which told us up to what index to take the prefix to. For example, prefix[i] = 2 means to take a prefix of word[0], word[1], word[2].


0            1.      2        3         4.            5.               6.              7             8 
["like", "god", "internal", "me", "internet", "interval", "intension", "face", "intrusion"]



ans[] = l2e, god, i6l, me, i6t, i6l, I7n, f2e, I7n

i = 2 
Hashset 
For (j = 3; j < len, j++){
    ans[j] = 


Set = (2, 5 )

ans[2] = abbr(dict.get(2), prefix index + 1)





Input: ["like", "god", "internal", "me", "internet", "interval", "intension", "face", "intrusion"]
Output: [“l2e","god","internal","me","i6t","interval","inte4n","f2e","intr4n"]

// correct
Make abbreviation for each word.
Then, check each word, if there are some strings which have same abbreviation with it, increase the prefix.

    public List<String> wordsAbbreviation(List<String> dict) {
        int len=dict.size();
        String[] ans=new String[len];
        int[] prefix=new int[len];
        for (int i=0;i<len;i++) {
            prefix[i]=1;
            ans[i]=makeAbbr(dict.get(i), 1); // make abbreviation for each string
        }
        for (int i=0;i<len;i++) {
            while (true) {
                HashSet<Integer> set=new HashSet<>();
                for (int j=i+1;j<len;j++) {
                    if (ans[j].equals(ans[i])) set.add(j); // check all strings with the same abbreviation
                }
                if (set.isEmpty()) break;
                set.add(i);
                for (int k: set) 
                    ans[k]=makeAbbr(dict.get(k), ++prefix[k]); // increase the prefix
            }
        }
        return Arrays.asList(ans);
    }

    private String makeAbbr(String s, int k) {
        if (k>=s.length()-2) return s;
        StringBuilder builder=new StringBuilder();
        builder.append(s.substring(0, k));
        builder.append(s.length()-1-k);
        builder.append(s.charAt(s.length()-1));
        return builder.toString();
    }





// not tested 

class Solution {
    public List<String> wordsAbbreviation(List<String> dict) {
        int N = words.size();
        String ans[] = new String[N];
        int[] prefix = new int[N];
        
        // abbrev all words 
        for(int i = 0; i < N; i++){
            ans[i] = abbr(words.get(i), 0);
        }
        
        for(int i = 0; i < N; i++){
            while(true){ // the only condition to break the while (true) loop is when the set is empty
                // which means there is no duplicate abbr for this word at dict[i] 
                HashSet<Integer> set = new HashSet<>();
                for(int j = i + 1; j < N; j++){
                    if(ans[i].equals(ans[j])){
                        set.add(j); // add the dup 's index 
                    }
                }
                if(set.isEmpty()) break; // if no dup, move on to the next word 
                // has duplicate 
                set.add(i); // now we have collected all the duplicate abbr 's index in the dic 
                // now it's time to extend the prefix 
                for(int index : set){
                    ans[index] = abbr(dict.get(index), prefix[index]++);
                }
            }
        }
        return Arrays.asList(ans); // turn array into a list 
    }
    private String abbr(String word, int start){
        int n = word.length();
        StringBuilder sb = new StringBuilder();
        sb.append(word.substring(0, i + 1)).append(n - i - 2).append(word.charAt(n - 1));
        return sb.toString(); // another way : do it with string + 
    }
}















Solution 2 : group + trie 

没看懂

let's group words based on length, first letter, and last letter, and discuss when words in a group do not share a longest common prefix.
Put the words of a group into a trie (prefix tree), and count at each node (representing some prefix P) the number of words with prefix P. If the count is 1, we know the prefix is unique.

猜你喜欢

转载自www.cnblogs.com/tobeabetterpig/p/9927015.html
今日推荐