问题描述:将一个给定字符串 s
根据给定的行数 numRows
,以从上往下、从左到右进行 Z 字形排列。
简单分析:
思路:拿到这个题目后,我首先想到了基数排序,模仿其原理,将不同的字符按照所在字符串的索引分装到不同的"木桶"中,最后合并木桶,即可得到最终的字符串。这个方法,需要单独开辟O(n)的空间存储数据,并且数据在原始字符串/桶/结果值之间移动,造成了时间的浪费。提交结果不是很理想。o(╥﹏╥)o
优化:基于第一种,不转存数据,每个桶作为一层,直接将每层的数据输出到结果值中。
编码:
方法1:仿基数排序的桶原理
class Solution {
public String convert(String s, int numRows) {
if (numRows <=0){
throw new RuntimeException("numRows <= 0");
}
if (numRows == 1){
return s;
}
// 定义numRows个桶用来存储字符
ArrayList<Character>[]bucket = new ArrayList[numRows];
for (int i = 0; i < numRows; i++) {
bucket[i] = new ArrayList<>();
}
// 将字符串中字符装入不同的桶中
for (int i = 0; i < s.length(); i++) {
bucket[index(i ,numRows)].add(s.charAt(i));
}
// 返回
StringBuilder builder = new StringBuilder();
for (int i = 0; i < numRows; i++) {
for (var ch : bucket[i]) {
builder.append(ch);
}
}
return builder.toString();
}
private int index(int i, int numRows){
// 单周期内数字个数
int circle = numRows* 2 - 2;
int cIndex = i % circle;
int mid = numRows - 1;
if (cIndex <= mid)
return cIndex;
return circle - cIndex;
}
}
方法二:优化方案
class Solution {
public String convert(String s, int numRows) {
if (numRows <=0){
throw new RuntimeException("numRows <= 0");
}
if (numRows == 1){
return s;
}
StringBuilder ret = new StringBuilder();
// 一个循环内的数字个数
int circle = (numRows - 1) * 2;
for (int level = 0; level < numRows; level++) {
for (int i = level; i < s.length(); i += circle) {
ret.append(s.charAt(i));
// 循环内的索引
int index = i % circle;
// 掐头去尾
if (index ==0 || index == numRows - 1)
continue;
// 循环内的对称点
int sIndex = i + 2 * (numRows - level - 1);
if(sIndex < s.length())
ret.append(s.charAt(sIndex));
}
}
return ret.toString();
}
}