Monday, May 12, 2014

LeetCode: Text Justification

Given an array of words and a length L, format the text such that each line has exactly L characters and is fully (left and right) justified.

You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ' ' when necessary so that each line has exactly L characters.

Extra spaces between words should be distributed as evenly as possible. If the number of spaces on a line do not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right.

For the last line of text, it should be left justified and no extra space is inserted between words.

For example,
words: ["This", "is", "an", "example", "of", "text", "justification."]
L: 16.

Return the formatted lines as:

[
   "This    is    an",
   "example  of text",
   "justification.  "
]

Note: Each word is guaranteed not to exceed L in length.

  • A line other than the last line might contain only one word. What should you do in this case?
    In this case, that line should be left-justified.

  • I cannot find a smart approach to solve this problem. Just do it step by step. If current line can accept one more word, push the word into current line. Otherwise push current line into final result and create a new line, then put the word into the new line.

    C++ Code:

    /*
     * func: push_back_line
     * goal: construct line into one string and push into vector
     * @param line: line vector
     * @param result: result vector
     * return:
     */
    void push_back_line(vector<string>& line, vector<string> &result){
        string word_line = "";
        for(const auto &it : line){
            word_line += it;
        }
        result.emplace_back(word_line);
    }
    
    /*
     * func: line_processing
     * goal: processing the current line, add spaces to make it fit the requirement
     * @param remaining: the number of spaces to be fit
     * @param line: word vector
     * return:
     */
    void line_processing(int remaining, vector<string>& line){
        //If there is only one word in the line
        if(line.size() == 1){
            while(remaining > 0){
                line[0] += ' ';
                --remaining;
            }
        }else{
            //Evenly distribute space
            int each = remaining / (line.size()-1);
            for(int m = 1; m<line.size(); ++m){
                for(int j=0; j < each; j++){
                    line[m] = ' ' + line[m];
                }
            }
            remaining %= (line.size()-1);
            int it = 1;
            while(remaining > 0){
                line[it] = ' ' + line[it];
                ++it;
                --remaining;
            }
        }
    }
    /*
     * func: full_justify
     * goal: format the text such that each line has exactly L characters
     * @param words: vector of words
     * @param L: maximum length of each line
     * return: vector of strings
     */
    vector<string> full_justify(const vector<string> &words, int L){
        int max_length = 0;
        for(const auto &it : words){
            max_length = std::max(static_cast<int>(it.length()), max_length);
        }
        if(max_length > L){
            return vector<string>();
        }
        vector<string> line;
        vector<string> result;
        int length = 0;
        for(int i=0; i < words.size(); ++i){
            if(length == 0){
                line.emplace_back(words[i]);
                length = words[i].length();
            }else{
                if( length + words[i].length() + 1> L){
                    line_processing(L - length, line);
                    push_back_line(line, result);
                    line.clear();
                    length = 0;
                    --i;
                }else{
                    line.emplace_back(' '+ words[i]);
                    length += words[i].length() + 1;
                }
            }
        }
        
        //Deal with the last line
        int remaining = L - length;
        //If there is only one word in the line
        while(remaining > 0){
            line[line.size()-1] += ' ';
            --remaining;
        }
        push_back_line(line, result);
        return result;
    }
    

    Python Code:

    # func: format the text such that each line has exactly L characters
    # @param words: list of words
    # @param L: the length
    # @return: list of lines after justification
    def full_justify(words, L):
        max_len = len(max(words, key=len))
        if max_len > L:
            return []
    
        result = []
        words_line = []
        length = 0
        i = 0
        while i < len(words):
            if not words_line:
                words_line.append(words[i])
                length = len(words[i])
                i += 1
            else:
                if length + len(words[i]) + 1 <= L:
                    words_line.append(' '+words[i])
                    length += len(words[i]) + 1
                    i += 1
                else:
                    #We have to push current line into result
                    spaces = L - length
                    #If there is only one word in words_line, append all space to the end
                    if len(words_line) == 1:
                        words_line[0] += ' ' * spaces
                    else:
                        #spaces evenly assign to each word
                        each_word_space = spaces / (len(words_line) - 1)
                        for k in xrange(1, len(words_line)):
                            words_line[k] = ' ' * each_word_space + words_line[k]
                        #Assigning remaining spaces
                        remaining_spaces = spaces % (len(words_line) - 1)
                        space_i = 1
                        while remaining_spaces > 0:
                            words_line[space_i] = ' ' + words_line[space_i]
                            space_i += 1
                            remaining_spaces -= 1
                    #Construct current line and push it into result
                    result.append(''.join(word for word in words_line))
                    words_line = []
                    length = 0
        #Append last line
        spaces = L - length
        result.append((''.join(word for word in words_line)) + (' ' * spaces))
        return result
    

    No comments:

    Post a Comment