package com.interview.dynamic; /** * Date 05/07/2015 * @author tusroy * * Video link - https://youtu.be/RORuwHiblPc * * Given a sequence of words, and a limit on the number of characters that can be put * in one line (line width). Put line breaks in the given sequence such that the * lines are printed neatly * * Solution: * Badness - We define badness has square of empty spaces in every line. So 2 empty space * on one line gets penalized as 4 (2^2) while 1 each empty space on 2 lines gets * penalized as 2(1 + 1). So we prefer 1 empty space on different lines over 2 empty space on * one line. * * For every range i,j(words from i to j) find the cost of putting them on one line. If words * from i to j cannot fit in one line cost will be infinite. Cost is calculated as square of * empty space left in line after fitting words from i to j. * * Then apply this formula to get places where words need to be going on new line. * minCost[i] = minCost[j] + cost[i][j-1] * Above formula will try every value of j from i to len and see which one gives minimum * cost to split words from i to len. * * Space complexity is O(n^2) * Time complexity is O(n^2) * * References: * http://www.geeksforgeeks.org/dynamic-programming-set-18-word-wrap/ */ public class TextJustification { public String justify(String words[], int width) { int cost[][] = new int[words.length][words.length]; //next 2 for loop is used to calculate cost of putting words from //i to j in one line. If words don't fit in one line then we put //Integer.MAX_VALUE there. for(int i=0 ; i < words.length; i++){ cost[i][i] = width - words[i].length(); for(int j=i+1; j < words.length; j++){ cost[i][j] = cost[i][j-1] - words[j].length() - 1; } } for(int i=0; i < words.length; i++){ for(int j=i; j < words.length; j++){ if(cost[i][j] < 0){ cost[i][j] = Integer.MAX_VALUE; }else{ cost[i][j] = (int)Math.pow(cost[i][j], 2); } } } //minCost from i to len is found by trying //j between i to len and checking which //one has min value int minCost[] = new int[words.length]; int result[] = new int[words.length]; for(int i = words.length-1; i >= 0 ; i--){ minCost[i] = cost[i][words.length-1]; result[i] = words.length; for(int j=words.length-1; j > i; j--){ if(cost[i][j-1] == Integer.MAX_VALUE){ continue; } if(minCost[i] > minCost[j] + cost[i][j-1]){ minCost[i] = minCost[j] + cost[i][j-1]; result[i] = j; } } } int i = 0; int j; System.out.println("Minimum cost is " + minCost[0]); System.out.println("\n"); //finally put all words with new line added in //string buffer and print it. StringBuilder builder = new StringBuilder(); do{ j = result[i]; for(int k=i; k < j; k++){ builder.append(words[k] + " "); } builder.append("\n"); i = j; }while(j < words.length); return builder.toString(); } public static void main(String args[]){ String words1[] = {"Tushar","likes","to","write","code","at", "free", "time"}; TextJustification awl = new TextJustification(); System.out.println(awl.justify(words1, 12)); } }