题目描述:
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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
题目难度:中等
分析:
题目说的是“Z”字形变换,其实还不如说“N”字形变换,这样还好理解点,因为排列的顺序就是字母“N”的书写顺序。这里是有规律的,直接按照规律去按行访问即可,第0行和最后一行(n-1)中间空着的数量是可以根据numRows来推算出来的,即对于所有整数 K, 每个间隔是:K(2∗numRows−2)。除去头尾以后,剩下中间的行 i 是:K(2∗numRows−2)+i 以及 (K+1)(2∗numRows−2)−i。
代码如下:
class Solution { public String convert(String s, int numRows) { // 如果只有一行,那么直接输出就行了。 if (numRows == 1) return s; StringBuilder res = new StringBuilder(); int l = s.length(); // 定义一个进位符,就是根据上面的规律,来决定下次应该进多少位 int carry = 2 * numRows - 2; // 外层for控制行数,一共有numRows行,下标从0开始 for (int i = 0; i < numRows; i++) { // 内层for控制每一行的元素个数,每次跳一个进位数 for (int j = 0; j + i < l; j += carry) { // 直接把当前下标的元素加入StringBuilder即可。 res.append(s.charAt(j + i)); /* 这里判断当前位于哪一行,如果不是第0行和最后一行的话, 那么肯定是中间行,中间行首个元素就是i,然后后面的元素就是 j + carry - i */ if (i != 0 && i != numRows - 1 && j + carry - i < l) { res.append(s.charAt(j + carry - i)); } } } // 最后输出即可 return res.toString(); } }
总结:
时间复杂度为:O ( n ) ,因为每个字符串都被访问过一次。对于这类题目,看似很复杂,其实找到规律以后就很简单了,不过这种题目个人觉得没什么意义,无聊的时候看看就行。