题目描述
1.1、直接思维
看到题目,就想到的办法:
class Solution {
public String convert(String s, int numRows) {
char[]str = s.toCharArray();
if(numRows<=1){
return s;
}
char[][]res = new char[numRows][s.length()/2+1];
int k=0;
int j=0;
int l=0;//列索引
int i=0;//行索引
while(j<str.length){
if(k==0){//向下走
for(i=0;i<numRows&&j<str.length;i++){
res[i][l] = str[j];
j++;
}
k=1;//改变方向
l++;//走到了尽头,列加1
}
if(k==1){//开始向上走
int row = numRows-2;
for(i=l;row>0&&j<str.length;i++){
res[row][i]= str[j];
row--;
j++;
}
l=i;
k=0;
}
}
StringBuilder sb = new StringBuilder();
for(int b=0;b<res.length;b++){
for(int t=0;t<res[b].length;t++){
if('\u0000'!=res[b][t]){//char数组默认值为0的字符值'\u000'
sb.append(res[b][t]);//遍历组合输出
}
}
}
return sb.toString();
}
}
1.2、直接思维第一次优化
将一些不必要的量去除:
class Solution {
public String convert(String s, int numRows) {
char[]str = s.toCharArray();
if(numRows<=1){
return s;
}
char[][]res = new char[numRows][s.length()/2+1];
int j=0;
int l=0;//列索引
int i;//行索引
while(j<str.length){
//向下走
for(i=0;i<numRows&&j<str.length;i++){
res[i][l] = str[j];
j++;
}
l++;
int row = numRows-2;
for(i=l;row>0&&j<str.length;i++){//斜向上走
res[row][i]= str[j];
row--;
j++;
}
l=i;
}
StringBuilder sb = new StringBuilder();//提取数据
for (char[] re : res) {
for (char c : re) {
if ('\u0000' != c) {
sb.append(c);
}
}
}
return sb.toString();
}
}
上面的算法主要是因为添加了二维数组,二维数组很多空值,而且导致时间复杂度O(N2)。那么我们还是模拟字符串的走向,进行添加。
1.3、第二次优化,转变使用类型
我们将二维数组改变。变成List<StringBuilder>
类型
每个StringBuilder代表一行数据,那么有n个StringBuilder。走向用一个flag表示。我们知道只有在第一行和最后一行,flag的值发生变换,走向改变。可得如下代码:
class Solution {
public String convert(String s, int numRows) {
if(numRows<2){
return s;
}
//模拟走向
List<StringBuilder> resRow = new ArrayList<>();
for(int i=0;i<numRows;i++){
resRow.add(new StringBuilder());//创建n行空字符串
}
int index=0,flag=1;//1表示向下走
for(char k:s.toCharArray()){
resRow.get(index).append(k);//刚开始是想下走
index+=flag;//开始走,向下则索引加1
if(index==0||index==numRows-1){
//遇到末行就要向上走,遇到首行方向重新向下走。
flag=-flag;
}
//这样,在模拟走的过程中我们不需要添加'\u0000';加大空间利用率
}
StringBuilder res =new StringBuilder();//将每行的字符串进行组合输出
for(StringBuilder k:resRow){
res.append(k.toString());
}
return res.toString();
}
}
时间复杂度上看,应该估计为O(N);空间复杂度为:O(N);
2.1、找规律实现
最后我们从提交击败百分比上,可以得知应该还能优化。那应该是数据的分布是有规律的。导致可以更加快 。于是找以下规律:
从行上看,第一行理解为8、0;第二行为8-2*1,0+2*1
的间隔索引,则最后一行为8-2*(n-1),0+2*(n-1)
的索引。于是可以写出代码:
class Solution {
public String convert(String s, int numRows) {
if(numRows<2){
return s;
}
List<StringBuilder> list = new ArrayList<>();
for(int i=0;i<numRows;i++){
list.add(new StringBuilder());
}//n行空字符串
int dlter=2*(numRows-1);//找到间隔初值
char[] chars = s.toCharArray();
for(int i=0;i<numRows&&i<chars.length;i++){
list.get(i).append(chars[i]);//初始化第一个值
int col;//间隔
if(i==0||i==numRows-1){//间隔为dlter、0
col = i+dlter;
while(col<chars.length){
list.get(i).append(chars[col]);
col+=dlter;
}
}else {//间隔为d1和d2;
int d1 = dlter-2*i;
int d2 = dlter-d1;
col = i+d1;//d1的间隔
while(col<chars.length){
list.get(i).append(chars[col]);
if((col+=d2)<chars.length)
list.get(i).append(chars[col]);
col+=d1;//8-2=6,下一次就是8-6=2
}
}
}
StringBuilder res =new StringBuilder();//将每行的字符串进行组合输出
for(StringBuilder k:list){
res.append(k.toString());
}
return res.toString();
}
}
2.2、找规律中的优化
在上面的应用里面,我们发现了我们所添加的元素是按照行添加的。所以我们不需要最后的合并操作。于是可以只用一个StringBuilder来实现:
class Solution {
public String convert(String s, int numRows) {
if(numRows<2){
return s;
}
StringBuilder list = new StringBuilder();
int dlter=2*(numRows-1);//找到间隔初值
char[] chars = s.toCharArray();
int n=chars.length;
for(int i=0;i<numRows&&i<n;i++){
list.append(chars[i]);//初始化第一个值
int col;//间隔
if(i==0||i==numRows-1){//间隔为dlter、0
col = i+dlter;
while(col<n){
list.append(chars[col]);
col+=dlter;
}
}else {//间隔为d1和d2;都大于0
int d1 = dlter-2*i;
int d2 = dlter-d1;
col = i+d1;//d1的间隔
while(col<n){
list.append(chars[col]);
if((col+=d2)<n)
list.append(chars[col]);
col+=d1;//8-2=6,下一次就是8-6=2
}
}
}
return list.toString();
}
}
最后完美提升了效率: