PAT 1031 Hello World for U (20分) 找规律按行输出即可

题目

Given any string of N (≥5) characters, you are asked to form the characters into the shape of U. For example, helloworld can be printed as:

h  d
e  l
l  r
lowo

That is, the characters must be printed in the original order, starting top-down from the left vertical line with n1​​ characters, then left to right along the bottom line with n​2​​ characters, and finally bottom-up along the vertical line with n​3​​ characters. And more, we would like U to be as squared as possible -- that is, it must be satisfied that n​1​​ =n​3​​ =max { k | k≤n​2​​ for all 3≤n​2​​ ≤N } with n​1​​ +n​2​​ +n​3​​ −2=N.

Input Specification:
Each input file contains one test case. Each case contains one string with no less than 5 and no more than 80 characters in a line. The string contains no white space.

Output Specification:
For each test case, print the input string in the shape of U as specified in the description.

Sample Input:
helloworld!
Sample Output:

h   !
e   d
l   l
lowor

题目解读

  • 给定一个长度在5-80之间、不包含空格的字符串,将它转变成 U 型 输出。
  • n1n3是左右两条竖线从上到下的字符个数,n2是底部横线从左到右的字符个数。
  • n​1​​ = n​3​​ = max { k | k ≤ n​2​​ for all 3 ≤ n​2 ​​ ≤ N } ; n1 + n2 + n3 - 2 = N

思路分析

这个题最关键的地方就是确定 U 的两竖有多高,一横有多宽,也就是确定n1,n2,n3
我们可以根据题目中的关系式n​1​​ = n​3​​ = max { k | k≤n​2​​ for all 3≤n​2​​ ≤N }得到n1<=n2,进一步推导得到 N + 2 = n1 + n2 + n3 >= n1 + n1 + n3 = 3 * n1 ==> n1 <= (N + 2) / 3
所以 n1 = (N + 2) / 3,n3 = n1,n2 = N - n1 - n3 = N - 2 * n1

接下来就是输出,可以初始化一个二维字符数组,刚开始填上空白,然后把U对应的位置填上,最后输出。

我这里采用的是直接按行输出。
比如题目给出的helloworld!,为了方便发现规律,我把索引标出来

0 h   ! 10
1 e   d 9
2 l   l 8
3 lowor 7
   456

发现,最后一行(U的那一横)上面的行(n1 - 1行),都是两个字符,每一行第一个字符就是原串按顺序输出的字符,然后中间有n2-2个空格,下一个字符在原串哪个位置呢??原串长度11,0+10 = 10,1 + 9 = 10, 2+8 = 10, 看出来么???两个字符在原串中的索引加起来等于原串的长度-1。

n1-1行第一个字符输出到原串第n1-2个位置上,至于最后一个横行,就接着这个位置输出原串,一共有n2个字符就可以了。(看索引就明白了)

完整代码

#include <iostream>
#include <string.h>

using namespace std;

/**
 * 题目大意:用所给字符串按U型输出。n1和n3是左右两条竖线从上到下的字符个数,n2是底部横线从左到右的字符个数。
 * 要求:n1 == n3; n1 >= n2; n1 + n2 + n3 - 2 = N 
 * N + 2 = n1 + n2 + n3 >= n1 + n1 + n3 = 3 * n1 ==> n1 <= (N + 2) / 3
 * 题目要求让 U 尽可能 "squared" 所以n1要尽可能大。因此n1取值 (N + 2) / 3
 */
int main() {

    char str[80];
    cin >> str;

    int len = strlen(str);
    int n1 = (len + 2) / 3, n2 = len - 2 * n1 +2;
    // 输出到原串哪个字符了
    int i = 0;

    // U的两竖线,最后一行之上的行(U的那一横之上),共n1-1行,
    for (; i < n1 - 1; ++i) {
        // 每一行第一个字符
        cout << str[i];
        // 中间有 n2 - 2个空格
        for (int j = 1; j < n2 - 1; ++j)
            cout << " ";
        // 每一行最后一个字符,这两字符在原串中的位置满足 x + y = len - 1
        cout << str[len - i - 1] << endl;
    }
    // 输出最后一行 n2个字符
    while(n2-- > 0)
        cout << str[i++];

    return 0;
}

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://vivi.run/archives/pat-10310helloworld-u