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. Assume that the length of each word is smaller than the line width. When line breaks are inserted there is a possibility that extra spaces are present in each line. The extra spaces includes spaces put at the end of every line except the last one.
The problem is to minimize the following total cost.
Total cost = Sum of cost of all lines, where cost of line is = (Number of extra spaces in the line)^2.
For example, consider the following string and line width M = 15
“Geeks for Geeks presents word wrap problem”
Following is the optimized arrangement of words in 3 lines
Geeks for Geeks
presents word
wrap problem
The total extra spaces in line 1 and line 2 are 0 and 2. Space for line 3 is not considered as it is not extra space as described above. So optimal value of total cost is 0 + 2*2 = 4.
Examples:
Input format: Input will consists of array of integers where each array element represents length of each word of string. For example, for string S = "Geeks for Geeks", input array will be arr[] = {5, 3, 5}. Output format: Output consists of a series of integers where two consecutive integers represent starting word and ending word of each line. Input : arr[] = {3, 2, 2, 5} Output : 1 1 2 3 4 4 Line number 1: From word no. 1 to 1 Line number 2: From word no. 2 to 3 Line number 3: From word no. 4 to 4 Input : arr[] = {3, 2, 2} Output : 1 1 2 2 3 3 Line number 1: From word no. 1 to 1 Line number 2: From word no. 2 to 2 Line number 3: From word no. 3 to 3
Approach: We have discussed a Dynamic Programming based solution of word wrap problem. The solution discussed used O(n^2) auxiliary space. The auxiliary space used can be reduced to O(n). The idea is to use two 1-D arrays dp[] and ans[], where dp[i] represents minimum cost of the line in which arr[i] is the first word and ans[i] represents index of last word present in line in which word arr[i] is the first word. Let k represents limit on number of characters in each line. Suppose for any line l the first word in that line is at index i in arr[]. The minimum cost of that line is stored in dp[i]. The last word in that line is at index j in arr[], where j can vary from i to n. Iterate over all values of j and keep track of number of characters added so far in line l. If number of characters are less than k then find cost of current line with these number of characters. Compare this cost with minimum cost find so far for this line in dp[i] and update dp[i] and ans[i] accordingly. Repeat above procedure for each value of i, 1 <= i <= n. The starting and ending words of each line will be at index i and index ans[i], where next value of i for line l+1 is ans[i] + 1.
Implementation:
C++
// C++ program for space optimized // solution of Word Wrap problem. #include <bits/stdc++.h> using namespace std; // Function to find space optimized // solution of Word Wrap problem. void solveWordWrap( int arr[], int n, int k) { int i, j; // Variable to store number of // characters in given line. int currlen; // Variable to store possible // minimum cost of line. int cost; // DP table in which dp[i] represents // cost of line starting with word // arr[i]. int dp[n]; // Array in which ans[i] store index // of last word in line starting with // word arr[i]. int ans[n]; // If only one word is present then // only one line is required. Cost // of last line is zero. Hence cost // of this line is zero. Ending point // is also n-1 as single word is // present. dp[n - 1] = 0; ans[n - 1] = n - 1; // Make each word first word of line // by iterating over each index in arr. for (i = n - 2; i >= 0; i--) { currlen = -1; dp[i] = INT_MAX; // Keep on adding words in current // line by iterating from starting // word upto last word in arr. for (j = i; j < n; j++) { // Update number of characters // in current line. arr[j] is // number of characters in // current word and 1 // represents space character // between two words. currlen += (arr[j] + 1); // If limit of characters // is violated then no more // words can be added to // current line. if (currlen > k) break ; // If current word that is // added to line is last // word of arr then current // line is last line. Cost of // last line is 0. Else cost // is square of extra spaces // plus cost of putting line // breaks in rest of words // from j+1 to n-1. if (j == n - 1) cost = 0; else cost = (k - currlen) * (k - currlen) + dp[j + 1]; // Check if this arrangement gives // minimum cost for line starting // with word arr[i]. if (cost < dp[i]) { dp[i] = cost; ans[i] = j; } } } // Print starting index and ending index // of words present in each line. i = 0; while (i < n) { cout << i + 1 << " " << ans[i] + 1 << " " ; i = ans[i] + 1; } } // Driver function int main() { int arr[] = { 3, 2, 2, 5 }; int n = sizeof (arr) / sizeof (arr[0]); int M = 6; solveWordWrap(arr, n, M); return 0; } |
Java
// Java program for space // optimized solution of // Word Wrap problem. import java.io.*; class GFG { // Function to find space // optimized solution of // Word Wrap problem. static void solveWordWrap( int arr[], int n, int k) { int i, j; // Variable to store // number of characters // in given line. int currlen; // Variable to store // possible minimum // cost of line. int cost; // DP table in which // dp[i] represents // cost of line starting // with word arr[i]. int dp[] = new int [n]; // Array in which ans[i] // store index of last // word in line starting // with word arr[i]. int ans[] = new int [n]; // If only one word is present // then only one line is required. // Cost of last line is zero. // Hence cost of this line is zero. // Ending point is also n-1 as // single word is present. dp[n - 1 ] = 0 ; ans[n - 1 ] = n - 1 ; // Make each word first // word of line by iterating // over each index in arr. for (i = n - 2 ; i >= 0 ; i--) { currlen = - 1 ; dp[i] = Integer.MAX_VALUE; // Keep on adding words in // current line by iterating // from starting word upto // last word in arr. for (j = i; j < n; j++) { // Update number of characters // in current line. arr[j] is // number of characters in // current word and 1 // represents space character // between two words. currlen += (arr[j] + 1 ); // If limit of characters // is violated then no more // words can be added to // current line. if (currlen > k) break ; // If current word that is // added to line is last // word of arr then current // line is last line. Cost of // last line is 0. Else cost // is square of extra spaces // plus cost of putting line // breaks in rest of words // from j+1 to n-1. if (j == n - 1 ) cost = 0 ; else cost = (k - currlen) * (k - currlen) + dp[j + 1 ]; // Check if this arrangement // gives minimum cost for // line starting with word // arr[i]. if (cost < dp[i]) { dp[i] = cost; ans[i] = j; } } } // Print starting index // and ending index of // words present in each line. i = 0 ; while (i < n) { System.out.print((i + 1 ) + " " + (ans[i] + 1 ) + " " ); i = ans[i] + 1 ; } } // Driver Code public static void main (String[] args) { int arr[] = { 3 , 2 , 2 , 5 }; int n = arr.length; int M = 6 ; solveWordWrap(arr, n, M); } } // This code is contributed // by anuj_67. |
Python 3
# Python 3 program for space optimized # solution of Word Wrap problem. import sys # Function to find space optimized # solution of Word Wrap problem. def solveWordWrap(arr, n, k): dp = [ 0 ] * n # Array in which ans[i] store index # of last word in line starting with # word arr[i]. ans = [ 0 ] * n # If only one word is present then # only one line is required. Cost # of last line is zero. Hence cost # of this line is zero. Ending point # is also n-1 as single word is # present. dp[n - 1 ] = 0 ans[n - 1 ] = n - 1 # Make each word first word of line # by iterating over each index in arr. for i in range (n - 2 , - 1 , - 1 ): currlen = - 1 dp[i] = sys.maxsize # Keep on adding words in current # line by iterating from starting # word upto last word in arr. for j in range (i, n): # Update number of characters # in current line. arr[j] is # number of characters in # current word and 1 # represents space character # between two words. currlen + = (arr[j] + 1 ) # If limit of characters # is violated then no more # words can be added to # current line. if (currlen > k): break # If current word that is # added to line is last # word of arr then current # line is last line. Cost of # last line is 0. Else cost # is square of extra spaces # plus cost of putting line # breaks in rest of words # from j+1 to n-1. if (j = = n - 1 ): cost = 0 else : cost = ((k - currlen) * (k - currlen) + dp[j + 1 ]) # Check if this arrangement gives # minimum cost for line starting # with word arr[i]. if (cost < dp[i]): dp[i] = cost ans[i] = j # Print starting index and ending index # of words present in each line. i = 0 while (i < n): print (i + 1 , ans[i] + 1 , end = " " ) i = ans[i] + 1 # Driver Code if __name__ = = "__main__" : arr = [ 3 , 2 , 2 , 5 ] n = len (arr) M = 6 solveWordWrap(arr, n, M) # This code is contributed by ita_c |
C#
// C# program for space // optimized solution of // Word Wrap problem. using System; class GFG { // Function to find space optimized // solution of Word Wrap problem. public static void solveWordWrap( int [] arr, int n, int k) { int i, j; // Variable to store number of // characters in given line. int currlen; // Variable to store possible // minimum cost of line. int cost; // DP table in which dp[i] // represents cost of line // starting with word arr[i]. int [] dp = new int [n]; // Array in which ans[i] store // index of last word in line // starting with word arr[i]. int [] ans = new int [n]; // If only one word is present // then only one line is required. // Cost of last line is zero. // Hence cost of this line is zero. // Ending point is also n-1 as // single word is present. dp[n - 1] = 0; ans[n - 1] = n - 1; // Make each word first // word of line by iterating // over each index in arr. for (i = n - 2; i >= 0; i--) { currlen = -1; dp[i] = int .MaxValue; // Keep on adding words in // current line by iterating // from starting word upto // last word in arr. for (j = i; j < n; j++) { // Update number of characters // in current line. arr[j] is // number of characters in // current word and 1 // represents space character // between two words. currlen += (arr[j] + 1); // If limit of characters // is violated then no more // words can be added to // current line. if (currlen > k) { break ; } // If current word that is // added to line is last // word of arr then current // line is last line. Cost of // last line is 0. Else cost // is square of extra spaces // plus cost of putting line // breaks in rest of words // from j+1 to n-1. if (j == n - 1) { cost = 0; } else { cost = (k - currlen) * (k - currlen) + dp[j + 1]; } // Check if this arrangement // gives minimum cost for // line starting with word // arr[i]. if (cost < dp[i]) { dp[i] = cost; ans[i] = j; } } } // Print starting index // and ending index of // words present in each line. i = 0; while (i < n) { Console.Write((i + 1) + " " + (ans[i] + 1) + " " ); i = ans[i] + 1; } } // Driver Code public static void Main( string [] args) { int [] arr = new int [] {3, 2, 2, 5}; int n = arr.Length; int M = 6; solveWordWrap(arr, n, M); } } // This code is contributed // by Shrikant13 |
PHP
<?php // PHP program for space optimized // solution of Word Wrap problem. // Function to find space optimized // solution of Word Wrap problem. function solveWordWrap( $arr , $n , $k ) { // Variable to store number of // characters in given line. $currlen ; // Variable to store possible // minimum cost of line. $cost ; // DP table in which dp[i] represents // cost of line starting with word // arr[i]. $dp = array (); // Array in which ans[i] store index // of last word in line starting with // word arr[i]. $ans = array (); // If only one word is present then // only one line is required. Cost // of last line is zero. Hence cost // of this line is zero. Ending point // is also n-1 as single word is // present. $dp [ $n - 1] = 0; $ans [ $n - 1] = $n - 1; // Make each word first word of line // by iterating over each index in arr. for ( $i = $n - 2; $i >= 0; $i --) { $currlen = -1; $dp [ $i ] = PHP_INT_MAX; // Keep on adding words in current // line by iterating from starting // word upto last word in arr. for ( $j = $i ; $j < $n ; $j ++) { // Update number of characters // in current line. arr[j] is // number of characters in // current word and 1 // represents space character // between two words. $currlen += ( $arr [ $j ] + 1); // If limit of characters // is violated then no more // words can be added to // current line. if ( $currlen > $k ) break ; // If current word that is // added to line is last // word of arr then current // line is last line. Cost of // last line is 0. Else cost // is square of extra spaces // plus cost of putting line // breaks in rest of words // from j+1 to n-1. if ( $j == $n - 1) $cost = 0; else $cost = ( $k - $currlen ) * ( $k - $currlen ) + $dp [ $j + 1]; // Check if this arrangement gives // minimum cost for line starting // with word arr[i]. if ( $cost < $dp [ $i ]) { $dp [ $i ] = $cost ; $ans [ $i ] = $j ; } } } // Print starting index and ending index // of words present in each line. $i = 0; while ( $i < $n ) { echo ( $i + 1) . " " . ( $ans [ $i ] + 1) . " " ; $i = $ans [ $i ] + 1; } } // Driver function $arr = array (3, 2, 2, 5); $n = sizeof( $arr ); $M = 6; solveWordWrap( $arr , $n , $M ); // This code is contributed // by Akanksha Rai ?> |
Javascript
<script> // Javascript program for space optimized // solution of Word Wrap problem. // Function to find space optimized // solution of Word Wrap problem. function solveWordWrap(arr, n, k) { var i, j; // Variable to store number of // characters in given line. var currlen; // Variable to store possible // minimum cost of line. var cost; // DP table in which dp[i] represents // cost of line starting with word // arr[i]. var dp = Array(n); // Array in which ans[i] store index // of last word in line starting with // word arr[i]. var ans = Array(n); // If only one word is present then // only one line is required. Cost // of last line is zero. Hence cost // of this line is zero. Ending point // is also n-1 as single word is // present. dp[n - 1] = 0; ans[n - 1] = n - 1; // Make each word first word of line // by iterating over each index in arr. for (i = n - 2; i >= 0; i--) { currlen = -1; dp[i] = 1000000000; // Keep on adding words in current // line by iterating from starting // word upto last word in arr. for (j = i; j < n; j++) { // Update number of characters // in current line. arr[j] is // number of characters in // current word and 1 // represents space character // between two words. currlen += (arr[j] + 1); // If limit of characters // is violated then no more // words can be added to // current line. if (currlen > k) break ; // If current word that is // added to line is last // word of arr then current // line is last line. Cost of // last line is 0. Else cost // is square of extra spaces // plus cost of putting line // breaks in rest of words // from j+1 to n-1. if (j == n - 1) cost = 0; else cost = (k - currlen) * (k - currlen) + dp[j + 1]; // Check if this arrangement gives // minimum cost for line starting // with word arr[i]. if (cost < dp[i]) { dp[i] = cost; ans[i] = j; } } } // Print starting index and ending index // of words present in each line. i = 0; while (i < n) { document.write( i + 1 + " " + (ans[i] + 1) + " " ); i = ans[i] + 1; } } // Driver function var arr = [ 3, 2, 2, 5 ]; var n = arr.length; var M = 6; solveWordWrap(arr, n, M); // This code is contributed by itsok. </script> |
1 1 2 3 4 4
Time Complexity: O(n^2)
Auxiliary Space: O(n), since n extra space has been taken.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!