问题 B: Hello World for U

U形字符串打印算法

题目描述
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 n2 characters, and finally bottom-up along the vertical line with n3 characters. And more, we would like U to be as squared as possible – that is, it must be satisfied that n1 = n3 = max { k| k <= n2 for all 3 <= n2 <= N } with n1 + n2 + n3 - 2 = N.

输入
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.

输出
For each test case, print the input string in the shape of U as specified in the description.

样例输入 Copy
helloworld!
样例输出 Copy
h !
e d
l l
lowor
提示
这一题需要解决的问题是将一个字符串写成U字形。拿到这一题的第一映像是U字的写法(可没有茴香豆的“茴”写法多),先是写第一排第一个字符,然后写第二排第一个字符……然后是最后一排,然后是倒数第二排……但在C语言中如果我们要这样写U字形的字符串就需要在数组中操作了。如果是直接输出的话,那只能自上至下一行一行输出。首先是第一行,写出第一个字符和最后一个字符,第二行写出第二个字符和倒数第二个字符……最后是最后一行。需要注意的是除了最后一行输出所有字符,前面每一行只输出两个字符。中间还有空格来隔开每行的两个字符(具体有多少空格,待会计算)。

思路有了,看看具体的要求。字符串的长度是N,n1,n3代表两边每列字符的数目。n2代表最后一行的字符数。题目中给了一个算式:

n1 = n3 = max { k| k <= n2 for all 3 <= n2 <= N } with n1 + n2 + n3 - 2 = N.

仔细研究这个算式,这里的k是不大于n2的,也就是说n1和n3是不大于n2且满足n1+n2+n3=N+2的最大值。那么自然有n1=n3=(N+2)/3,n2=N+2-(n1+n3)。也就是说设side为两边的字符数(包括最后一行的两端),则side=n1=n3=(N+2)/3。设mid为最后一行除去两端的两个字符后剩下的字符数,mid=N-side*2(总长度减去两边的字符数)。同时mid也是我们输出除最后一行外前面所有行需要空出的空格数。

最后如何在第一行输出第一个字符和最后一个字符呢?那自然是str[0]和str[len-1-i](len为字符串的长度,也就是N)。

于是问题完美解决,步骤如下:

1)计算字符串长度len;

2)计算两边的字符数side=(len+2)/3;

3)计算最后一行中间的字符数(前面每行中间的空格数);

4)输出每行相应的字符。

由于该题目不难,也没有什么需要特别注意的,我也就不写注意点了。具体细节详见参考代码。

#include <iostream>
#include <string>
using namespace std;

int main(void)
{
    string a;
    cin>>a;
    int len=a.size();
    int side = (len+2)/3;
    int mid=len-side*2;
    for(int i=0;i<side;i++)
    {
        cout<<a[i];
        if(i==side-1)
        {
            for(int k=i+1;k<len-i-1;k++)
            {
                cout<<a[k];
            }
        }
        else
        {
            for(int j=0;j<mid;j++)
            {
                cout<<" ";
            }
        }
        
        
        cout<<a[len-i-1];
        cout<<endl;
    }

    system("pause");
    return 0;
}
以下是实现该功能的C代码以及解释: ### 实现代码 ```c #include <stdio.h> #include <ctype.h> // 用于字符分类函数 int main() { int counts[26] = {0}; // 创建一个数组,存储每个字母的计数 char ch; printf("请输入一行文本(以回车键结束):\n"); // 使用 getchar() 逐个读取输入字符 while ((ch = getchar()) != '\n') { // 当输入不是换行符时继续读取 if (isalpha(ch)) { // 如果是字母 ch = tolower(ch); // 转换为小写字母 counts[ch - 'a']++; // 对应字母计数加1 } } // 输出统计结果 for (int i = 0; i < 26; i++) { char upper = 'A' + i; // 大写字母 char lower = 'a' + i; // 小写字母 printf("%c(%c):%d\n", upper, lower, counts[i]); } return 0; } ``` --- ### 解释 #### 1. **程序逻辑** - 程序通过`getchar()`逐个读取用户输入的字符。 - 使用`isalpha()`判断字符是否为字母,如果是字母,则将其转换为小写(使用`tolower()`),并更新对应的计数。 - 最后遍历字母表,输出每个字母及其出现次数。 #### 2. **关键步骤** - **初始化计数数组**: - 定义一个大小为26的整型数组`counts`,用于存储每个字母的出现次数。初始值均为0。 - **读取输入**: - 使用`getchar()`逐个读取字符,直到遇到换行符`\n`为止。 - 对于每个字符,使用`isalpha()`判断是否为字母。 - 如果是字母,使用`tolower()`将其转换为小写字母,并通过`ch - 'a'`计算其在字母表中的索引,更新对应计数。 - **输出结果**: - 遍历字母表(从'A'到'Z'),输出每个字母及其出现次数。 #### 3. **函数说明** - `isalpha(ch)`:判断字符`ch`是否为字母。 - `tolower(ch)`:将字符`ch`转换为小写字母。 - `getchar()`:从标准输入流中读取下一个字符。 #### 4. **边界条件** - 输入可能包含非字母字符(如空格、标点符号等),这些字符不会被统计。 - 输入可能为空行,此时所有字母的计数均为0。 --- ### 示例运行结果 #### 输入: ``` Hello World ``` #### 输出: ``` A(a):0 B(b):0 C(c):0 D(d):1 E(e):1 F(f):0 G(g):0 H(h):1 I(i):0 J(j):0 K(k):0 L(l):3 M(m):0 N(n):0 O(o):2 P(p):0 Q(q):0 R(r):1 S(s):0 T(t):0 U(u):0 V(v):0 W(w):1 X(x):0 Y(y):0 Z(z):0 ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值