双指针控制数组
题目
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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) ;
示例
输入: s = "LEETCODEISHIRING" , numRows = 3 输出: "LCIRETOESIIGEDHN"
输入: s = "LEETCODEISHIRING" , numRows = 4 输出: "LDREOEIIECIHNTSG" 解释: L D R E O E I I E C I H N T S G
考察知识点
指针、数组
核心思想
通过从左向右迭代字符串,我们可以轻松地确定字符位于 Z 字形图案中的哪一行。
题目理解:字符串 s 是以 Z字形为顺序存储的字符串,目标是按行打印。设 numRows
行字符串分别为 \(s\_{1}\) 、 \(s\_{2}\) 、\(s\_{3}\) 、......\(s\_{n}\) 则容易发现:按顺序遍历字符串 s 时,每个字符 c 在 Z 字形中对应的 行索引 先从 \(s\_{1}\) 增大至 \(s\_{n}\) ,再从 \(s\_{n}\) 减小至\(s\_{1}\) ,如此反复。重点是发现这个规律。
因此,解决方案为:模拟这个行索引的变化,在遍历 s 中把每个字符填到正确的行 res[i]
。类似于构造了一个指针确定应该将字符串放到那个位置。 - 算法流程: 按顺序遍历字符串 s; 1. res[i] += c
: 把每个字符 c 填入对应行 \(s_{i}\) 2. i += flag
: 更新当前字符 c 对应的行索引; 3. flag = - flag
:在达到 Z字形转折点时,执行反向。 - 复杂度分析: 时间复杂度 \(O(n)\) :遍历一遍字符串 s; 空间复杂度 \(O(n)\) :各行字符串共占用 \(O(n)\) 额外空间。
参考连接
指针方法解决
python版本
一个失败的例子
时间复杂度和空间复杂度都是\(O(n^2)\) ,系统判定超出时间限制 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 class Solution : def convert (self, s: str , numRows: int ) -> str: if len (s) <= numRows: return s matrix = [] inter = numRows - 2 start = 0 end = numRows all_in = True while end<=len (s): if all_in: _segment = s[start:end] if len (_segment) < numRows: _segment += "#" * (numRows-len (_segment)) matrix.append(list (_segment)) start += numRows if end == len (s): break if end+inter <= len (s): end += inter else : end = len (s) all_in = False else : _segment = s[start:end] for j in range (len (_segment)): tmp_str = "#" *(numRows-j-2 ) + _segment[j] + "#" *(j+1 ) matrix.append(list (tmp_str)) start = end if end == len (s): break if end+numRows < len (s): end += numRows else : end = len (s) all_in = True return_str = "" for i in range (numRows): for j in range (len (matrix)): return_str += matrix[j][i] return_str = return_str.replace("#" , "" ) return return_str print("leet code accept!!!" ) s = ["PAYPALISHIRING" , "PAYPALISHIRING" , "A" ] numRows = [3 , 4 , 2 ] Answer = ["PAHNAPLSIIGYIR" , "PINALSIGYAHRPI" , "A" ]if __name__ == "__main__" : solution = Solution() for i in range (len (s)): print("-" *50 ) result = solution.convert(s[i], numRows[i]) print(result==Answer[i])
数组方法,十分简洁且高效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution : def convert (self, s: str , numRows: int ) -> str: if numRows < 2 : return s res = ["" for _ in range (numRows)] i, flag = 0 , -1 for c in s: res[i] += c if i == 0 or i == numRows - 1 : flag = -flag i += flag tmp_res = '' for i in res: tmp_res += i return tmp_res print("leet code accept!!!" ) s = ["PAYPALISHIRING" , "PAYPALISHIRING" , "A" ] numRows = [3 , 4 , 2 ] Answer = ["PAHNAPLSIIGYIR" , "PINALSIGYAHRPI" , "A" ]if __name__ == "__main__" : solution = Solution() for i in range (len (s)): print("-" *50 ) result = solution.convert(s[i], numRows[i]) print(result==Answer[i])
时间复杂度和空间复杂度都是\(O(n)\)
56 ms
13.2 MB
return "".join(res)
88 ms
13 MB
return tmp_res
这说明尽量不调用API做字符串处理,会减少耗时。
有效语法糖