L1-002 打印沙漏(20分)[java][python]

4 阅读3分钟

题目ID:L1-002 分数:20分 作者:陈越 单位:浙江大学

题目描述

本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个"*",要求按下列格式打印

*****
 ***
  *
 ***
*****

所谓"沙漏形状",是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。

给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。

输入格式

输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。

输出格式

首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。

输入样例

19 *

输出样例

*****
 ***
  *
 ***
*****
2

代码长度限制

16 KB

解题思路

沙漏形状的规律分析:

  1. 上半部分:从最大行(假设有 2*n+1 个符号)递减到 1

    • 行数:n
    • 符号数:1, 3, 5, 7, ..., 2*n-1
    • 总符号数:n²
  2. 下半部分:从 3 递增到 2*n-1

    • 行数:n-1 行
    • 符号数:3, 5, 7, ..., 2*n-1
    • 总符号数:(n-1)²
  3. 完整沙漏:2*n² - 1 行,总共需要 2*n² - 1 个符号

解题步骤:

  1. 根据总符号数 N,找到最大的 n 使得 2*n*n - 1 <= N
  2. 计算剩余符号数:remain = N - (2*n*n - 1)
  3. 打印上半部分(递减到 1)
  4. 打印下半部分(从 3 开始递增)

代码实现

Java

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        String symbol = sc.next();
        
        // 找到最大的 n,使得 2*n*n - 1 <= N
        int n = 1;
        while (2 * n * n - 1 <= N) {
            n++;
        }
        n--;  // 回退一步
        
        int remain = N - (2 * n * n - 1);
        
        // 打印上半部分(递减到 1)
        for (int i = n; i >= 1; i--) {
            int spaces = n - i;  // 左侧空格数
            int count = 2 * i - 1;  // 符号数
            printLine(spaces, count, symbol);
        }
        
        // 打印下半部分(从 3 开始递增)
        for (int i = 2; i <= n; i++) {
            int spaces = n - i;  // 左侧空格数
            int count = 2 * i - 1;  // 符号数
            printLine(spaces, count, symbol);
        }
        
        System.out.println(remain);
    }
    
    private static void printLine(int spaces, int count, String symbol) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < spaces; i++) {
            sb.append(" ");
        }
        for (int i = 0; i < count; i++) {
            sb.append(symbol);
        }
        System.out.println(sb.toString());
    }
}

Python

def print_hourglass(n, symbol):
    # 打印一行
    def print_line(spaces, count):
        print(" " * spaces + symbol * count)
    
    # 打印上半部分(递减到 1)
    for i in range(n, 0, -1):
        spaces = n - i
        count = 2 * i - 1
        print_line(spaces, count)
    
    # 打印下半部分(从 3 开始递增)
    for i in range(2, n + 1):
        spaces = n - i
        count = 2 * i - 1
        print_line(spaces, count)


def main():
    data = input().split()
    N = int(data[0])
    symbol = data[1]
    
    # 找到最大的 n,使得 2*n*n - 1 <= N
    n = 1
    while 2 * n * n - 1 <= N:
        n += 1
    n -= 1
    
    remain = N - (2 * n * n - 1)
    
    print_hourglass(n, symbol)
    print(remain)


if __name__ == "__main__":
    main()

运行验证

Java 测试

输入输出结果
19 ****** / *** / * / *** / ***** / 2

Python 测试

输入输出结果
19 ****** / *** / * / *** / ***** / 2
17 ****** / *** / * / *** / ***** / 0
20 @***** / *** / * / *** / ***** / 3

复杂度分析

  • 时间复杂度:O(n²),其中 n 约为 √(N/2),即打印的字符总数
  • 空间复杂度:O(1),只使用常数额外空间

总结

本题关键在于发现沙漏形状的数学规律:一个完整的沙漏需要 2*n*n - 1 个符号。通过等差数列求和可以推导出这个公式,从而确定能组成的最大沙漏尺寸。打印时需要控制好每行的空格数和符号数。