📜  自动换行问题(优化空间的解决方案)

📅  最后修改于: 2021-05-06 21:42:34             🧑  作者: Mango

给定一系列单词,并限制一行中可以输入的字符数(行宽)。按给定的顺序放置换行符,以使行被整齐地打印。假设每个单词的长度小于行宽。当插入换行符时,每行中都可能存在多余的空格。多余的空格包括除最后一行以外的每行末尾的空格。
问题是使以下总成本最小化。
总成本=所有行的成本总和,其中行的成本为=(行中多余空格的数量)^ 2。
例如,考虑以下字符串和线宽M = 15
“ Geeks for Geeks提出了自动换行问题”
以下是3行中单词的优化排列
极客换极客
提出词
包装问题
第1行和第2行的总额外空间为0和2。不考虑第3行的空间,因为它不是如上所述的额外空间。因此,总成本的最佳值为0 + 2 * 2 = 4。

例子:

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 

推荐:在继续解决方案之前,请先在“实践”上解决它。

方法:我们讨论了基于动态编程的自动换行问题的解决方案。讨论的解决方案使用O(n ^ 2)辅助空间。可以将使用的辅助空间减小为O(n)。这个想法是使用两个一维数组dp []和ans [],其中dp [i]代表其中arr [i]是第一个单词,而ans [i]代表最后一个单词的索引行的最小开销在单词arr [i]是第一个单词的行中。令k代表每行中字符数的限制。假设对于任何l行,该行中的第一个单词都位于arr []中的索引i处。该行的最低成本存储在dp [i]中。该行的最后一个单词在arr []中的索引j处,其中j可以从i变为n。遍历j的所有值,并跟踪到目前为止在l行中添加的字符数。如果字符数少于k,则用这些字符数查找当前行的成本。将此成本与到目前为止在dp [i]中针对该行找到的最低成本进行比较,并相应地更新dp [i]和ans [i]。对i的每个值重复上述过程,1 <= i <= n。每行的开始和结束词将在索引i和索引ans [i]处,其中行l + 1的i的下一个值是ans [i] + 1。

执行:

C++
// C++ program for space optimized
// solution of Word Wrap problem.
  
#include 
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
= 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
?>


输出:
1 1 2 3 4 4

时间复杂度: O(n ^ 2)
辅助空间: O(n)