#C0E107. 华为OD机试E卷 -箱子之字形摆放
华为OD机试E卷 -箱子之字形摆放
华为OD机试E卷 -箱子之字形摆放(Java & Python& JS & C++ & C )
https://blog.csdn.net/banxia_frontend/article/details/143732149
最新华为OD机试
题目描述
有一批箱子(形式为字符串,设为str),
要求将这批箱子按从上到下以之字形的顺序摆放在宽度为 n 的空地,请输出箱子的摆放位置。
例如:箱子ABCDEFG,空地宽度为3,摆放结果如图:
则输出结果为:
AFG
BE
CD
输入描述
输入一行字符串,通过空格分隔,前面部分为字母或数字组成的字符串str,表示箱子;
后面部分为数字n,表示空地的宽度。例如:
ABCDEFG 3
输出描述
输出只有一个整数,表示会影响或结果的交换方案个数。
箱子摆放结果,如题目示例所示
AFG
BE
CD
备注
- 请不要在最后一行输出额外的空行
- str只包含字母和数字,1 <= len(str) <= 1000
- 1 <= n <= 1000
示例1
输入
ABCDEFG 3
输出
AFG
BE
CD
说明
解题思路
题意
有点像这道题:https://leetcode.cn/problems/zigzag-conversion/description/
-
题目背景:有一批箱子,用一个字符串
str
表示,每个字符代表一个箱子。将这些箱子以“之字形”的顺序放在一个宽度为n
的空地中。 -
之字形摆放:在一个宽度为
n
的空地中,从上到下、从左到右,以“之字形”摆放箱子,摆放规则如下:- 第一列:从上到下摆放
n
个箱子。 - 第二列:从下到上摆放
n
个箱子。 - 第三列:再从上到下摆放,以此类推,每列摆放方向交替。
- 每列在摆放时的位置会交替,因此称之为“之字形”摆放。
- 第一列:从上到下摆放
-
输出要求:按照每一列的结果从左到右依次输出。每行代表一列的箱子内容,不要输出额外的空行。
摆放过程:
- 第一列:从上到下摆放
A
、B
、C
- 第二列:从下到上摆放
D
、E
、F
- 第三列:从上到下摆放
G
摆放结构可以写成如下形式:
AFG
BE
CD
解法1:数学推导
通过例子推导之字形摆放的规律及公式:
例子:字符串 ABCDEFG
,宽度 n = 3
摆放位置表如下:
字符 | 行列位置 | 字符 | 行列位置 | 字符 | 行列位置 |
---|---|---|---|---|---|
A | (0,0) | F | (0,1) | G | (0,2) |
B | (1,0) | E | (1,1) | ||
C | (2,0) | D | (2,1) |
字符对应公式分析
-
第一列(正向放置):
- A 第 0 个字符,位置 (0,0),行数公式:
i % n = 0 % 3 = 0
- B 第 1 个字符,位置 (1,0),行数公式:
i % n = 1 % 3 = 1
- C 第 2 个字符,位置 (2,0),行数公式:
i % n = 2 % 3 = 2
- A 第 0 个字符,位置 (0,0),行数公式:
-
第二列(反向放置):
- D 第 3 个字符,位置 (2,1),行数公式:
n - 1 - (i % n) = 3 - 1 - (3 % 3) = 2
- E 第 4 个字符,位置 (1,1),行数公式:
n - 1 - (i % n) = 3 - 1 - (4 % 3) = 1
- F 第 5 个字符,位置 (0,1),行数公式:
n - 1 - (i % n) = 3 - 1 - (5 % 3) = 0
- D 第 3 个字符,位置 (2,1),行数公式:
-
第三列(正向放置):
- G 第 6 个字符,位置 (0,2),行数公式:
i % n = 6 % 3 = 0
- G 第 6 个字符,位置 (0,2),行数公式:
总结规律
- 正向列(从上到下放置):
行数 = i % n
- 反向列(从下到上放置):
行数 = n - 1 - (i % n)
最终公式
- 初始时,正向列公式:
行数 = i % n
- 当摆放方向切换时:
- 反向列公式:
行数 = n - 1 - (i % n)
- 反向列公式:
- 按列顺序依次交替应用以上公式。
解法2 : 模拟
模拟之字形摆放
- 行索引控制:使用
current_row
作为摆放行的指针,初始位置设为 0,指向第一行。 - 方向控制:通过布尔变量
is_ascending
控制行索引的增减方向。初始值为True
,表示从上往下移动。
遍历与摆放过程
-
逐字符遍历:程序依次取出每个字符并放入
placement_grid
中,形成摆放过程的模拟。- 当
is_ascending
为True
时,行索引增加,字符会逐行向下摆放;一旦达到底部(current_row == width
),方向改变为False
,模拟反弹到顶部的效果。 - 当
is_ascending
为False
时,行索引减少,字符会逐行向上摆放;一旦到达顶部(current_row == -1
),方向恢复为True
,模拟向下的循环效果。
- 当
-
字符追加:将字符追加到
current_row
对应的行中,实现之字形效果。通过+=
操作符将字符直接加入到对应行的字符串中。
模拟示例
假设输入为 ABCDEFG 3
,模拟过程如下:
placement_grid
初始为["", "", ""]
- 按照之字形摆放:
A
放在第 0 行 →["A", "", ""]
B
放在第 1 行 →["A", "B", ""]
C
放在第 2 行 →["A", "B", "C"]
D
回到第 1 行 →["A", "BD", "C"]
E
回到第 0 行 →["AE", "BD", "C"]
F
到第 1 行 →["AE", "BDF", "C"]
G
到第 2 行 →["AE", "BDF", "CG"]
最终输出:
AE
BDF
CG
总结
从模拟角度来看,代码通过控制当前行指针和方向标志,模拟箱子字符的之字形摆放过程,实现字符在不同行之间的循环移动,形成题目描述的摆放效果。
Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.next();
int n = scanner.nextInt();
int length = str.length();
// 初始化二维字符数组 matrix,用于存放箱子的摆放位置
// 行数为 n(空地宽度),列数为 (length + n - 1) / n,确保能够容纳所有字符
char[][] matrix = new char[n][(length + n - 1) / n];
// 定义布尔变量 reverse 用于标记当前方向(之字形摆放)
boolean reverse = false;
int row = 0, col = 0; // 初始化当前行和列位置
// 遍历每个字符,将其放入二维数组 matrix 中
for (int i = 0; i < length; i++) {
// 将当前字符放入 matrix 的指定位置
matrix[row][col] = str.charAt(i);
// 根据当前方向更新行索引 row 的位置
if (reverse) {
row--; // 如果是反向,行位置减少
} else {
row++; // 如果是正向,行位置增加
}
// 检查是否达到边界,如果是,则换行并反转方向
if (row == n || row < 0) {
reverse = !reverse; // 反转方向
row = reverse ? n - 1 : 0; // 重置行索引:如果是反向则从底部开始,否则从顶部开始
col++; // 列索引增加一位,进入下一列
}
}
// 遍历二维数组 matrix,输出摆放结果
for (int i = 0; i < n; i++) { // 遍历每一行
for (int j = 0; j < matrix[i].length; j++) { // 遍历每一列
if (matrix[i][j] != 0) { // 判断当前位置是否有字符
System.out.print(matrix[i][j]); // 输出字符
}
}
System.out.println(); // 每行输出完后换行
}
}
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.next(); // 读取箱子字符串
int n = scanner.nextInt(); // 读取空地宽度
int length = str.length(); // 获取箱子字符串长度
// 初始化二维字符数组用于存储摆放结果
char[][] matrix = new char[n][(length + n - 1) / n];
boolean reverse = true; // 标记当前行的方向
for (int i = 0; i < length; i++) {
int k = i % n; // 计算行号
if (k == 0) reverse = !reverse; // 每到新列改变方向
if (reverse) k = n - 1 - k; // 如果当前是反向,则调整行号
// 将当前字符放入对应的行列
matrix[k][i / n] = str.charAt(i);
}
// 遍历并输出矩阵
for (int i = 0; i < n; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] != 0) { // 检查是否有字符
System.out.print(matrix[i][j]);
}
}
System.out.println();
}
}
}
Python
# 导入标准输入模块
def main():
# 读取输入字符串和空地宽度
inputs = input().split()
str_val = inputs[0] # 第一个输入为字符串
n = int(inputs[1]) # 第二个输入为宽度n
length = len(str_val) # 字符串长度
# 初始化二维字符数组,行数为n,列数根据字符串长度计算
matrix = [[''] * ((length + n - 1) // n) for _ in range(n)]
reverse = False # 定义方向标志,False表示向下,True表示向上
row, col = 0, 0 # 初始化行、列索引
# 遍历字符串,将字符存入二维数组
for i in range(length):
matrix[row][col] = str_val[i] # 将当前字符放入相应位置
# 更新行索引,根据方向变化
if reverse:
row -= 1
else:
row += 1
# 到达边界时调整方向并移动列
if row == n or row < 0:
reverse = not reverse # 反转方向
row = n - 1 if reverse else 0 # 根据方向重置行索引
col += 1 # 移动到下一列
# 输出二维数组中的字符
for row in matrix:
print("".join(char for char in row if char)) # 过滤空白字符
if __name__ == "__main__":
main()
def main():
# 读取输入的字符串和宽度
str_val = input().split()
box_str = str_val[0] # 获取箱子字符串
n = int(str_val[1]) # 获取空地宽度
length = len(box_str) # 获取字符串长度
# 初始化二维数组,用于存放字符
matrix = [[''] * ((length + n - 1) // n) for _ in range(n)]
reverse = True # 定义方向标记
for i in range(length):
k = i % n # 计算行号
if k == 0:
reverse = not reverse # 每到新列时改变方向
if reverse:
k = n - 1 - k # 如果反向,调整行号
# 将当前字符放入二维数组中的指定位置
matrix[k][i // n] = box_str[i]
# 输出结果
for row in matrix:
print("".join(char for char in row if char)) # 过滤掉空白字符
if __name__ == "__main__":
main()
JavaScript
// 读取输入并处理字符串及宽度
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('line', (input) => {
const inputs = input.split(' ');
const strVal = inputs[0]; // 第一个输入是字符串
const n = parseInt(inputs[1]); // 第二个输入是宽度n
const length = strVal.length; // 字符串长度
// 初始化二维数组
const matrix = new Array(parseInt(n)).fill().map(() => []);
let reverse = false; // 方向标志
let row = 0, col = 0; // 初始化行、列索引
// 遍历字符串,将字符存入二维数组
for (let i = 0; i < length; i++) {
matrix[row][col] = strVal[i];
if (reverse) {
row--;
} else {
row++;
}
if (row === n || row < 0) {
reverse = !reverse; // 反转方向
row = reverse ? n - 1 : 0;
col++; // 进入下一列
}
}
// 输出结果
for (let i = 0; i < n; i++) {
console.log(matrix[i].filter(char => char).join('')); // 输出每行字符
}
rl.close();
});
// Node.js 版本,读取输入并处理箱子字符串和宽度
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on("line", (input) => {
const [boxStr, nStr] = input.split(" ");
const n = parseInt(nStr);
const length = boxStr.length;
// 初始化二维数组
const matrix = new Array(parseInt(n)).fill().map(() => []);
let reverse = true; // 定义方向标记
for (let i = 0; i < length; i++) {
let k = i % n; // 计算行号
if (k === 0) reverse = !reverse; // 新列时改变方向
if (reverse) k = n - 1 - k; // 如果反向,则调整行号
// 将字符放入矩阵
matrix[k][Math.floor(i / n)] = boxStr[i];
}
// 输出矩阵
matrix.forEach(row => {
console.log(row.filter(char => char).join('')); // 过滤空白字符
});
rl.close();
});
C++
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
string str;
int n;
cin >> str >> n;
int length = str.length(); // 获取字符串长度
// 初始化二维字符数组
vector<vector<char>> matrix(n, vector<char>((length + n - 1) / n, '\0'));
bool reverse = false; // 方向标志
int row = 0, col = 0; // 初始化行、列位置
// 将字符按照规则存入二维数组
for (int i = 0; i < length; i++) {
matrix[row][col] = str[i];
if (reverse) {
row--; // 反向摆放
} else {
row++; // 正向摆放
}
if (row == n || row < 0) {
reverse = !reverse; // 反转方向
row = reverse ? n - 1 : 0;
col++; // 换到下一列
}
}
// 输出结果
for (int i = 0; i < n; i++) {
for (int j = 0; j < matrix[i].size(); j++) {
if (matrix[i][j] != '\0') { // 跳过空字符
cout << matrix[i][j];
}
}
cout << endl; // 换行
}
return 0;
}
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
string str;
int n;
cin >> str >> n;
int length = str.length();
// 初始化二维数组
vector<vector<char>> matrix(n, vector<char>((length + n - 1) / n, '\0'));
bool reverse = true; // 定义方向标记
for (int i = 0; i < length; i++) {
int k = i % n; // 计算行号
if (k == 0) reverse = !reverse; // 每列改变方向
if (reverse) k = n - 1 - k; // 若反向则调整行号
// 将字符存入矩阵
matrix[k][i / n] = str[i];
}
// 输出矩阵
for (int i = 0; i < n; i++) {
for (int j = 0; j < matrix[i].size(); j++) {
if (matrix[i][j] != '\0') { // 过滤空白字符
cout << matrix[i][j];
}
}
cout << endl;
}
return 0;
}
C语言
#include <stdio.h>
#include <string.h>
int main() {
char str[1001]; // 假设最大长度为1000
int n;
// 读取字符串和宽度
scanf("%s %d", str, &n);
int length = strlen(str); // 计算字符串长度
// 初始化二维数组
char matrix[n][(length + n - 1) / n];
memset(matrix, 0, sizeof(matrix)); // 初始化为0
int reverse = 0; // 方向标志,0表示向下,1表示向上
int row = 0, col = 0; // 初始化行、列索引
// 遍历字符串
for (int i = 0; i < length; i++) {
matrix[row][col] = str[i]; // 将字符存入矩阵
if (reverse) {
row--; // 向上移动
} else {
row++; // 向下移动
}
if (row == n || row < 0) {
reverse = !reverse; // 改变方向
row = reverse ? n - 1 : 0;
col++; // 进入下一列
}
}
// 输出二维数组的字符
for (int i = 0; i < n; i++) {
for (int j = 0; j < (length + n - 1) / n; j++) {
if (matrix[i][j] != 0) {
putchar(matrix[i][j]);
}
}
putchar('\n'); // 每行输出后换行
}
return 0;
}
#include <stdio.h>
#include <string.h>
int main() {
char str[1001]; // 假设最大字符串长度为1000
int n;
scanf("%s %d", str, &n);
int length = strlen(str);
// 初始化二维数组,行数为n,列数根据字符串长度确定
char matrix[n][(length + n - 1) / n];
memset(matrix, 0, sizeof(matrix)); // 初始化为0
int reverse = 1; // 定义方向标记,1表示当前为反向
for (int i = 0; i < length; i++) {
int k = i % n; // 计算行号
if (k == 0) reverse = !reverse; // 每到新列改变方向
if (reverse) k = n - 1 - k; // 如果反向,则调整行号
// 将字符放入矩阵指定位置
matrix[k][i / n] = str[i];
}
// 输出矩阵内容
for (int i = 0; i < n; i++) {
for (int j = 0; j < (length + n - 1) / n; j++) {
if (matrix[i][j] != 0) { // 检查是否有字符
putchar(matrix[i][j]);
}
}
putchar('\n'); // 每行结束后换行
}
return 0;
}
完整用例
用例1
ABCDEFG 3
用例2
123456789 4
用例3
ABCDEFGHIJKL 2
用例4
12345 5
用例5
ABCDEFGHIJ 9
用例6
ZYXWVUTSRQPONMLKJIHGFEDCBA 6
用例7
ABCDEFGHIJKLMNOPQRSTUVWX 4
用例8
987654321 3
用例9
ABCDEFGHIJKLMNO 7
用例10
AB2CD2E3FG1HIJ5K5LM6NO 7