华为OD机试 - 箱子之字形摆放问题详解及C++/Java/JavaScript/Python代码实现
在华为OD机试中,箱子之字形摆放问题是一个经典的数组处理和模拟算法问题。它不仅考察了对二维数组的操作能力,还涉及到字符串的处理与数据结构的设计。本文将对该题目进行详细解析,并提供C++、Java、JavaScript和Python四种语言的实现。希望通过本文,读者能够全面理解题目的解题思路,熟悉多种编程语言的实现技巧。
一、题目描述
1.1 题目背景
我们有一批箱子,用一个字符串来表示每个箱子上的编号。我们需要将这些箱子按照之字形顺序摆放在宽度为n
的空地上,并输出它们的摆放位置。之字形摆放要求每行的箱子是交替从左到右,或者从右到左摆放的,形成类似“Z”字形的排列。
1.2 输入描述
输入只有一行字符串,格式为:
str n
其中,str
是表示箱子的字符串,n
是空地的宽度,表示摆放箱子的行数。箱子的字符串由字母和数字组成,n
是正整数。
1.3 输出描述
按照题目要求,输出最终的箱子摆放结果。每行输出一组摆放好的箱子,并且不应该输出多余的空行。
1.4 输入输出示例
示例 1
输入:
ABCDEFG 3
输出:
AFG
BE
CD
解释:箱子从左到右摆放,宽度为 3,因此可以理解为第一行顺序排,第二行从右往左,第三行再从左往右,依次交替摆放。
示例 2
输入:
HELLOWORLD 4
输出:
HOD
ELW
LOR
L
二、解题思路
2.1 思路分析
为了正确地按照之字形摆放箱子,我们可以将这个问题分解为以下几个步骤:
-
初始化矩阵:根据宽度
n
,创建一个二维数组(列表/向量),每一行用于存放按照之字形摆放的字符。 -
确定每个字符的位置:通过遍历字符串中的每个字符,使用行索引来确定字符应该放置在哪一行。之字形的规律可以通过如下方式进行判断:
- 如果当前字符应该从左往右摆放,则按照正常顺序填充。
- 如果当前字符应该从右往左摆放,则需要将字符放置在倒数位置。
-
交替顺序控制:通过对当前字符的索引值进行模运算,判断当前行是需要从左到右还是从右到左摆放。可以通过一个标志位来控制当前行的摆放方向。
-
输出矩阵:最后将每一行的字符拼接成字符串输出。
2.2 行索引的控制公式
摆放顺序的规律可以通过分析字符位置和行索引的关系总结如下:
- 行索引公式:
i % n
,其中i
表示当前字符的位置。 - 如果当前列是从左到右,则直接使用
i % n
。 - 如果当前列是从右到左,则计算方式为
n - 1 - (i % n)
。
2.3 算法步骤总结
- 初始化一个二维列表(或向量),其长度为
n
,每个元素用于存储该行的箱子编号。 - 逐个遍历字符串中的字符,计算字符应放置的行索引,并根据之字形的规律进行排列。
- 最后按行输出结果。
三、代码实现
3.1 C++ 代码实现
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
string str;
int n;
cin >> str >> n;
// 创建一个二维向量用于存储箱子摆放结果
vector<vector<char>> matrix(n);
bool reverse = true; // 控制之字形顺序的标志位
for (int i = 0; i < str.length(); i++) {
int k = i % n; // 计算字符应放置的行索引
if (k == 0) reverse = !reverse; // 每次从新行开始改变摆放顺序
if (reverse) k = n - 1 - k; // 若从右到左摆放,则调整索引
matrix[k].push_back(str[i]); // 将字符放入对应行
}
// 输出结果
for (const vector<char>& list : matrix) {
for (char character : list) {
cout << character;
}
cout << endl;
}
return 0;
}
3.2 JavaScript 代码实现
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.on("line", (input) => {
const [str, n] = input.split(" ");
const width = parseInt(n);
const matrix = new Array(width).fill().map(() => []); // 初始化矩阵
let reverse = true; // 交替顺序控制
for (let i = 0; i < str.length; i++) {
let row = i % width;
if (row === 0) reverse = !reverse; // 每次行变化时,调整顺序
if (reverse) row = width - 1 - row; // 若是从右往左摆放,则调整行索引
matrix[row].push(str[i]); // 放置箱子
}
// 输出摆放结果
matrix.forEach(row => {
console.log(row.join(''));
});
});
3.3 Java 代码实现
import java.util.ArrayList;
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(); // 输入宽度
ArrayList<ArrayList<Character>> matrix = new ArrayList<>(n); // 初始化矩阵
for (int i = 0; i < n; i++) {
matrix.add(new ArrayList<>());
}
boolean reverse = true; // 控制之字形摆放顺序
for (int i = 0; i < str.length(); i++) {
int row = i % n;
if (row == 0) reverse = !reverse; // 改变摆放方向
if (reverse) row = n - 1 - row;
matrix.get(row).add(str.charAt(i));
}
// 输出矩阵
for (ArrayList<Character> list : matrix) {
for (char character : list) {
System.out.print(character);
}
System.out.println();
}
}
}
3.4 Python 代码实现
# 读取输入
boxes, width = input().split()
width = int(width)
# 初始化二维数组
matrix = [[] for _ in range(width)]
reverse = True # 用于控制之字形摆放方向
# 遍历所有的箱子
for i, box in enumerate(boxes):
row = i % width # 计算当前箱子应该放在哪一行
if row == 0:
reverse = not reverse # 改变方向
if reverse:
row = width - 1 - row # 如果是从右到左摆放,则计算倒数行
matrix[row].append(box) # 将箱子放入矩阵
# 输出结果
for line in matrix:
print("".join(line))
四、复杂度分析
-
时间复杂度:所有语言的实现中,我们只需要遍历字符串一次,因此时间复杂度为
O(len(str))
。每个字符的操作(如插入、输出)都是常数时间操作,因此整体复杂度是线性的。 -
空间复杂度:由于需要存储字符串中每个字符的位置,因此空间复杂度也为
O(len(str))
。此外,额外的空间开销还包括二维数组的存储,约为O(n)
,其中n
是输入的宽度。
五、总结
通过这道“箱子之字形摆放”的题目,我们练习了如何通过二维数组和索引计算,巧妙实现复杂的字符摆放方式。无论是C++、JavaScript、Java还是Python,核心的思路都是一致的:通过行索引控制字符位置,并交替改变行方向。
在面试或机试中
,这类题目既考察了编程基础,又考验了对于规律的敏感性,掌握这样的题型对于通过华为OD机试非常有帮助。
参考网站:
- 华为OD官方考试页面
- CSDN相关题目解析