【问题标题】:Need help implementing a certain logic that will fill a text to a certain width.需要帮助实现将文本填充到特定宽度的特定逻辑。
【发布时间】:2017-07-01 05:14:47
【问题描述】:

任务是在一定宽度内对齐文本。

user inputs: Hello my name is Harrry. This is a sample text input that nobody 
             will enter.

output: What text width do you want?

user inputs: 15

output: |Hello  my  name|
        |is Harrry. This| 
        |is   a   sample|
        |text       that| 
        |nobody     will|
        |enter.         |

基本上,该行的宽度必须为 15 个空格,包括空格。此外,如果该行中的下一个单词不能放入 15,它将完全跳过。如果一行中有多个单词,它将尝试在每个单词之间平均分配空格。例如,请参阅“是样本”的行。

我使用 getline(...) 创建了一个向量,所有这些和整个文本都保存在一个向量中。但是,我有点坚持前进。我尝试使用多个 for 循环,但我似乎根本无法跳过行甚至超出间距。

再次重申,不希望或期望任何人解决此问题,但如果您能在我应该考虑的逻辑/算法方面引导我走向正确的方向,我将不胜感激。

【问题讨论】:

  • 您需要提供一些您已经完成的工作的示例,以显示您为获得所需帮助所做的努力。请查看How to ask on SO 以获得更好的想法。

标签: c++ loops vector logic


【解决方案1】:

您应该考虑这个动态编程解决方案。

将文本分成“好”行

由于我们不知道需要在哪里换行以获得良好的理由,因此我们开始猜测该段落的换行位置。 (即我们猜测是否应该在两个单词之间中断,并以第二个单词作为下一行的开头)。

你注意到什么了吗?我们蛮横的!

请注意,如果我们找不到一个足够小的单词以适合当前行的剩余空间,我们会在当前行的单词之间插入空格。因此,当前行中的空格取决于可能进入下一行或上一行的单词。这就是依赖!

你是暴力破解,你有依赖,DP来了!

现在让我们定义一个状态来确定我们解决这个问题的路径上的位置。

State[i : j],表示输入的原始单词序列中从第 i 个单词到第 j 个单词的单词行。

现在,您已经有了问题的状态,让我们尝试定义这些状态是如何相关的

由于我们所有的子问题状态都只是一堆单词,我们不能只比较每个状态的单词并确定哪个更好。这里 better 描述了使用行宽来保持特定行中单词之间的最大字符和最小空格。因此,我们定义了一个参数,该参数将衡量从第 i 个单词到第 j 个单词的单词列表的优劣度。 (回想一下我们对子问题状态的定义)。这基本上是在评估我们的每个子问题状态。

一个简单的比较因素是:

为单词行[i : j]定义badness(i, j)

例如, 如果总长度 > 页面宽度,则无穷大, else (页面宽度 - 当前行中单词的总长度)3

为了让事情变得更简单,只考虑给定文本的后缀并应用此算法。这会将 DP 表的大小从 N*N 减少到 N。

所以,为了完成,让我们用 DP 术语明确我们想要什么,

  1. 子问题 = min.后缀词的坏处[i :]

    =⇒ 子问题数 = Θ(n) 其中 n = 单词数

  2. 猜测 = 第一行在哪里结束,比如 i : j

    =⇒ 没有。 j = n - i = O(n) 的选择

  3. 递归关系子问题之间:

    • DP[i] = min(badness (i, j) + DP[j] for j in range (i + 1, n + 1)) • DP[n] = 0

=⇒ 每个子问题的时间 = Θ(n)

所以,总时间 = Θ(n^2)。

另外,我将在确定每行中的单词后,如何在单词之间插入空格。

【讨论】:

    【解决方案2】:

    逻辑是:

    1) 将单词放入数组中

    2) 遍历单词数组

    3) 计算每个单词中的字符数,并检查直到它们小于或等于文本宽度(如果大于文本宽度则跳过)。记住在超过 15 个之前构成总数的单词数(例如记住 3 个单词得到 9 个字符,留出 6 个空格)

    4) 将所需的空格数除以(字数 - 1)

    5) 写下这些单词,每次写相同数量的空格。

    应该能达到我希望的效果。

    【讨论】:

      【解决方案3】:

      您显然已经知道如何解决这个问题,因为您已经生成了示例输出。

      也许可以重新解决您最初的问题,用文字写下您在每个步骤中所做的事情......

      例如

      1. 打印要求句子的文本。
      2. 接受意见
      3. 将输入拆分为单词。
      4. 打印要求宽度的文本。
      5. ...

      如果您卡在任何级别,请将详细信息展开为子步骤。

      我希望将计算出适合一行的单词序列的问题分开。

      那么每个单词之间要加多少空格。

      【讨论】:

        【解决方案4】:

        下面是一个打印一行的例子,在你找到要打印的字数以及该行的起始字是什么之后。

            std::cout << "|";
            numOfSpaces = lineWidth - numOfCharsUsedByWords;
            /*
             * If we have three words |word1 word2 word3| in a line
             * ideally the spaces to print between then are 1 less than the words
             */
            int spaceChunks = numOfWordsInLine - 1;
            /*
             * Print the words from starting point to num of words
             * you can print in a line
             */
            for (j = 0; j < numOfWordsInLine; ++j) {
                /*
                 * Calculation for the number of spaces to print
                 * after every word
                 */
                int spacesToPrint = 0;
                if (spaceChunks <= 1) {
                  /*
                   * if one/two words then one 
                   * chunk of spaces between so fill then up
                   */
                   spacesToPrint = numOfSpaces;
                } else {
                  /*
                   * Here its just segmenting a number into chunks 
                   * example: segment 7 into 3 parts, will become 3 + 2 + 2
                   *          7 to 3 = (7%3) + (7/3) = 1 + 2 = 3
                   *          4 to 2 = (4%2) + (4/2) = 0 + 2 = 2
                   *          2 to 1 = (2%1) + (2/1) = 0 + 2 = 2
                   */
                   spacesToPrint = (numOfSpaces % spaceChunks) + (numOfSpaces / spaceChunks);
                }
                numOfSpaces -= spacesToPrint;
                spaceChunks--;
                cout << words[j + lineStartIdx];
                for (int space = 0; space < spacesToPrint; space++) {
                    std::cout << " ";
                }
            }
            std::cout << "|" << std::endl;
        

        希望此代码有所帮助。此外,您还需要考虑如果设置的宽度小于最大字长会发生什么。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-11-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-08
          • 2021-11-05
          相关资源
          最近更新 更多