#### 一、问题分析
给定一个三角形 `triangle`,要求找出自顶向下的最小路径和。每次移动只能到下一行相邻的节点(当前下标 `i` 或 `i+1`)。例如,三角形如下时:
```
2
3 4
6 5 7
4 1 8 3
```
#### 二、代码框架搭建
##### 1. 输入处理与三角形构建
```java
Scanner sc = new Scanner(System.in);
List<List<Integer>> triangle = new ArrayList<>();
System.out.print("请输入三角形的最大行数: ");
int maxRows = sc.nextInt();
sc.nextLine(); // 清除输入缓冲区中的换行符
for (int i = 0; i < maxRows; i++) {
List<Integer> row = new ArrayList<>();
System.out.printf("请输入第%d行的元素(用空格分隔):", i + 1);
String[] input = sc.nextLine().trim().split("\\s+");
for (String num : input) {
if (!num.isEmpty()) {
row.add(Integer.parseInt(num));
}
}
triangle.add(row); // 将当前行添加到三角形中
}
```
- **`sc.nextLine()` 的作用**:`nextInt()` 读取输入后不会读取行末的换行符,需要用 `sc.nextLine()` 清除缓冲区。
- **`split("\\s+")`**:按一个或多个空格分割输入,确保处理不规范的输入。
- **逐行构建**:每行的元素存储在 `List<Integer> row` 中,最终形成二维列表 `triangle`。
##### 2. 三角形打印
```java
for (int i = 0; i < maxRows; i++) {
int spaces = maxRows - i - 1;
for (int j = 0; j < spaces; j++) {
System.out.print(" ");
}
for (int j = 0; j < triangle.get(i).size(); j++) {
System.out.print(triangle.get(i).get(j) + " ");
}
System.out.println();
}
```
- **空格计算**:每行前导空格数为 `maxRows - i - 1`,使三角形右对齐显示。
- **逐行输出元素**:遍历每行的元素并打印。
---
#### 深入解析代码细节
---
##### **1. `String[] input` 的含义**
```java
String[] input = sc.nextLine().trim().split("\\s+");
```
- **作用**:
这一行代码的作用是将用户输入的一行数据(例如 `"3 4 5"`)按空格分割成一个字符串数组。
- `sc.nextLine()`:读取用户输入的一整行(包括空格)。
- `trim()`:去除输入字符串首尾的空格(避免输入前后误输入空格)。
- `split("\\s+")`:按一个或多个连续空格分割字符串。例如,输入 `" 6 5 7 "` 会被分割为 `["6", "5", "7"]`。
- **示例**:
假设用户输入 `" 4 1 8 3 "`(前后有空格),经过处理后:
- `trim()` → `"4 1 8 3"`
- `split("\\s+")` → `["4", "1", "8", "3"]`
最终 `input` 数组保存这些分割后的字符串。
---
##### **2. `println` 与 `print` 的区别**
| 方法 | 作用 | 示例 |
|-----------------------|----------------------------------------------------------------------|----------------------------------------------------------------------|
| `System.out.print()` | 输出内容后**不换行**,光标停留在输出末尾。 | `System.out.print("A");`<br>`System.out.print("B");` → 输出 `AB` |
| `System.out.println()`| 输出内容后**自动换行**,光标移动到下一行开头。 | `System.out.println("A");`<br>`System.out.println("B");` → 输出:<br>`A`<br>`B` |
- **代码中的实际应用**:
```java
// 打印三角形时,每行元素用 print(保持在一行)
for (int j = 0; j < triangle.get(i).size(); j++) {
System.out.print(triangle.get(i).get(j) + " ");
}
System.out.println(); // 换行到下一行
```
扩展:
1. `printf` 的作用**
`System.out.printf()` 是 Java 中用于**格式化输出**的方法。它的核心功能是通过**格式字符串**控制输出的样式,并动态插入变量值。与 `print` 和 `println` 相比,`printf` 可以更精细地控制输出的对齐方式、数字格式、字符串占位等。
- **语法**:
```java
System.out.printf("格式字符串", 参数1, 参数2, ...);
```
- **特点**:
- **不自动换行**:与 `print` 类似,输出后光标停留在末尾,需手动添加换行符 `%n`。
- **支持复杂格式化**:例如对齐文本、控制小数位数、日期时间格式等。
---
##### **2. 格式说明符(Format Specifiers)**
`printf` 通过格式说明符(如 `%d`, `%s`, `%f`)定义变量的输出格式。以下是常见说明符:
| 说明符 | 作用 | 示例 | 输出结果 |
|----------|------------------------------|--------------------------|---------------|
| `%d` | 整数(十进制) | `printf("%d", 25);` | `25` |
| `%f` | 浮点数 | `printf("%.2f", 3.1415);`| `3.14` |
| `%s` | 字符串 | `printf("%s", "Hello");` | `Hello` |
| `%n` | 换行符(平台无关) | `printf("A%nB");` | `A`<br>`B` |
| `%5d` | 固定宽度5,右对齐整数 | `printf("%5d", 10);` | ` 10` |
| `%-5s` | 固定宽度5,左对齐字符串 | `printf("%-5s", "Hi");` | `Hi ` |
---
##### **3. `triangle.add(row)` 的作用**
```java
List<List<Integer>> triangle = new ArrayList<>();
for (int i = 0; i < maxRows; i++) {
List<Integer> row = new ArrayList<>();
// ... 读取用户输入并填充 row ...
triangle.add(row); // 将当前行添加到三角形中
}
```
- **功能**:
将当前行的数据(`row` 列表)添加到二维列表 `triangle` 中,逐行构建完整的三角形数据结构。
- `triangle` 是一个 `List`,每个元素本身也是一个 `List<Integer>`(表示一行)。
- `triangle.add(row)` 会将新的一行追加到 `triangle` 的末尾。
- **示例**:
假设用户输入如下:
```
第1行:2
第2行:3 4
第3行:6 5 7
```
则 `triangle` 的结构为:
```java
[
[2],
[3, 4],
[6, 5, 7]
]
```
---
#### **代码流程总结**
1. **读取输入**:
- 用户输入行数和每行元素。
- 通过 `split("\\s+")` 处理不规则空格输入。
2. **构建三角形**:
- 逐行将数据添加到 `triangle` 中。
3. **打印三角形**:
- 通过计算空格数实现右对齐格式。
- 使用 `print` 和 `println` 控制输出格式。
---
#### **附:常见问题**
- **为什么用 `split("\\s+")` 而不是 `split(" ")`?**
`\\s+` 可以匹配**一个或多个连续空格**,避免空字符串(例如输入 `"3 4"` 会被正确分割为 `["3", "4"]`)。
- **为什么需要 `trim()`?**
防止用户输入前后误加空格(例如 `" 3 4 "` → 处理后变为 `"3 4"`)。
- **`triangle.add(row)` 会覆盖之前的数据吗?**
不会。每次循环都会创建一个新的 `row` 对象,`triangle` 保存的是对它的引用,因此各行数据独立。