该题出自LeetCode算法题第6题
https://leetcode-cn.com/problems/zigzag-conversion/
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"
示例 2:
输入: s = "LEETCODEISHIRING", numRows = 4
输出: "LDREOEIIECIHNTSG"
解释:
L D R
E O E I I
E C I H N
T S G
在我刚看见这个题的时候首先想到的是暴力破解,但是总觉得不太优雅。于是开始整理其中的规律。
不管怎么想都会用到String.charAt(index);
既然字符串不是固定的,那是否可以用下标代替呢?于是乎
0 4 8 12
1 3 5 7 9 11 13 15
2 6 10 14
这个规律其实并不难。但是如果行数不为3呢?
0 6 12
1 5 7 11 13
2 4 8 10 14
3 9 15
这就又头疼了
而且第一个的规律还要在第二个适用。
好吧。我就不买关子了。我就直接将我的思考草稿贴出来吧
// 3
//0 0 4 8 12 (3+1)*0 (3+1)*1 (3+1)*2
//1 1 3 5 7 9 11 13 15 (3+1)*0+-1[-1 1] (3+1)*1+-1[3 5] (3+1)*2+-1[7 9]
//2 2 6 10 14 (3+1)*0+2 (3+1)*1+2 (3+1)*2+2
//
// 4
//0 0 6 12 (4+2)*0 (4+2)*1 (4+2)*2
//1 1 5 7 11 13 (4+2)*0+-1 (4+2)*1+-1 (4+2)*2+-1
//2 2 4 8 10 14 (4+2)*0+-2 (4+2)*1+-2 (4+2)*2+-2
//3 3 9 15 (4+2)*0+3 (4+2)*1+3 (4+2)*2+3
//
// 5
//0 0 8 16 (5+3)*0
//1 1 7 9 15 17 (5+3)*0+-1
//2 2 6 10 14 18 (5+3)*0+-2
//3 3 5 11 13 19 (5+3)*0+-3
//4 4 12 20 (5+3)*0+4
//
// 6
//0 0 10 18 20 (6+4)*0
//1 1 9 11 17 21 (6+4)*0+-1
//2 2 8 12 16 22 (6+4)*0+-2
//3 3 7 13 15 23 (6+4)*0+-3
//4 4 6 14 24 (6+4)*0+-4
//5 5 15 25 (6+4)*0+5
以上草稿看懂第一个三行的就可以理解了。只不过每个例子中的中间行需要注意一下。
就是第一列只能加,不能减,不然就会出现多余的负数。
既然思路出来了,那么后面就是代码实现了。
package com.leetcode;
/**
* 将一个给定字符串根据给定的行数,以从上往下,从左到右进行Z字型排列。
* 示例
* "LEETCODEISHIRING"
* 排列
* L C I R
* ETOESIIG
* EDHN
* @author HF
*
*/
public class LeetCodeDemo06 {
public static void main(String[] args) {
// 3
//0 0 4 8 12 (3+1)*0 (3+1)*1 (3+1)*2
//1 1 3 5 7 9 11 13 15 (3+1)*0+-1[-1 1] (3+1)*1+-1[3 5] (3+1)*2+-1[7 9]
//2 2 6 10 14 (3+1)*0+2 (3+1)*1+2 (3+1)*2+2
//
// 4
//0 0 6 12 (4+2)*0 (4+2)*1 (4+2)*2
//1 1 5 7 11 13 (4+2)*0+-1 (4+2)*1+-1 (4+2)*2+-1
//2 2 4 8 10 14 (4+2)*0+-2 (4+2)*1+-2 (4+2)*2+-2
//3 3 9 15 (4+2)*0+3 (4+2)*1+3 (4+2)*2+3
//
// 5
//0 0 8 16 (5+3)*0
//1 1 7 9 15 17 (5+3)*0+-1
//2 2 6 10 14 18 (5+3)*0+-2
//3 3 5 11 13 19 (5+3)*0+-3
//4 4 12 20 (5+3)*0+4
//
// 6
//0 0 10 18 20 (6+4)*0
//1 1 9 11 17 21 (6+4)*0+-1
//2 2 8 12 16 22 (6+4)*0+-2
//3 3 7 13 15 23 (6+4)*0+-3
//4 4 6 14 24 (6+4)*0+-4
//5 5 15 25 (6+4)*0+5
String str = "LEETCODEISHIRING";
int rowNum = 3;
String zStr = getZstr(str, rowNum);
System.out.println(zStr);
}
public static String getZstr(String str,int rowNum) {
long startTime = System.nanoTime();
//获取字符串长度
int length = str.length();
//重组字符串数组
char[] strChar = new char[length];
//数组下标
int index = 0;
//循环行数
for(int i=0; i<rowNum; i++) {
//每行的列数
int count = 0;
while(true) {
//第一行和最后一行的算法一致,中间行数每次循环需要多添加一列
if(i>0 && i<rowNum-1) {
int indexNum = (2*rowNum-2)*count-i;
//判断下标是否超出原字符串长度
if(indexNum >= length) {
break;
}
//中间行第一次只能算加 相减下标为负数(去除)
if(indexNum > 0) {
strChar[index] = str.charAt(indexNum);
index++;
}
}
int indexNum = (2*rowNum-2)*count+i;
if(indexNum >= length) {
break;
}
strChar[index] = str.charAt(indexNum);
count++;
index++;
}
}
long endTime = System.nanoTime();
System.out.println("运行时长: " + (endTime-startTime) + " ns");
return String.copyValueOf(strChar);
}
}
运行结果
你们没有看错,就是 ‘’纳秒‘’。一毫秒都不到