这是我参与更文挑战的第6天,活动详情查看: 更文挑战
第6天,继续挑战第6题。这题一下子没想到什么好办法,先用暴力写法写出来。
题目
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。
示例 1:
输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"
示例 2:
输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
思路
一下子没想到什么好办法,还是先暴力求解吧。看了2个例子后,能明白题意就是一个字符串,先向下写,再向右上方写,循环往复,起始也不是Z字形,有点像倒Z。
以示例1为例来说,可以先对字母先分组一下:下图中红色框起来的是1个大组,蓝色框起来的是1个小组。每个大组包含了2个小组,2个小组不是对称的,要区分奇数小组和偶数小组。
可以使用一个二维数组来存储这个Z字形的形状,这个二维数组的行数就是numRows,列数可以根据大组的个数算出来,每个大组占用numRows-1列。然后遍历原始数组,根据下标判断是在哪个大组哪个小组,进而确认在二维数据中的位置,都遍历完成后,重新从上到下遍、从左到右历这个二维数组就能得到新的字符串
Java版本代码
class Solution {
public String convert(String s, int numRows) {
int length = s.length();
if (length == 1 || numRows == 1) {
return s;
}
// 每小组的元素个数
int groupNum = numRows - 1;
// 每个大组包含2个小组
int bigGroupNum = groupNum * 2;
// 每大组占据itemNum列,计算出最大需要的列数
int items = length / bigGroupNum;
// 不能整除时,最多会多出1组
if (length % bigGroupNum> 0) {
items = items + 1;
}
// 这里的itemNum是每大组占据groupNum列,items含义是总共有多少个大组
int maxColumn = groupNum * items;
Character[][] characters = new Character[numRows][maxColumn];
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
// 计算出当前字符在第几小组和第几大组,从0开始
int groupIndex = i / groupNum;
int bigGroupIndex = i / bigGroupNum;
// 计算出当前字符在小组内是第几个字符
int itemIndex = i % groupNum;
if (groupIndex % 2 == 0) {
// 偶数小组,向正下方
characters[itemIndex][groupNum*bigGroupIndex] = c;
} else {
// 奇数小组,向右上方
characters[numRows - 1 - itemIndex][groupNum*bigGroupIndex + itemIndex] = c;
}
}
char[] chars = new char[length];
int index = 0;
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < maxColumn; j++) {
if (characters[i][j] != null) {
chars[index++] = characters[i][j];
}
if (index == length) {
break;
}
}
}
return new String(chars);
}
}