简说Python,号主老表,Python终身学习者,数据分析爱好者,从18年开始分享Python知识,原创文章227篇,写过Python、SQL、Excel入门文章,也写过Web开发、数据分析文章,老表还总结整理了一份2022Python学习资料和电子书资源,关注后私信回复:2022 即可领取。
一、写在前面
好久没刷题了,最近看了点啥,备受鼓舞,决定每天刷一刷,也是一个和大家沟通交流的渠道,更具体的我为什么选择又开始刷题,下回再和大家分享,不搞悬疑,我发现的秘密可以见评论区。
前期不打算建相关学习交流群,不过Python学习交流群还是一直开放的哈,那么就开始今天的刷题吧。
LeetCode 第18篇刷题笔记传输门:继续刷Leetcode,第18篇。
今天给大家分享的是老表刷LeetCode 第十九篇:Z字形变换,为面试而生,期待你的加入。
❝Use the utility in the API is recommended in the project. But if you use it in an interview, you will definitely fail .
❞
二、今日题目
将一个给「定字符串」根据「给定的行数」,以「从上往下、从左到右进」行 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
❝来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zigzag-conversion
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
❞
三、 分析
这个题目,看着有点复杂,需要好好读和理解题目,首先确定输入、输出、其他变量、变换逻辑这三部分:
输入:字符串 输出:字符串 其他变量:给定的行数 变换逻辑:字符串以从上往下、从左到右进行遍历输出成 Z 字形排列
从变换逻辑来看,可以知道,主要是考察字符串的遍历。
四、解题
这里给大家分享两个大佬的解题方法。
1. Leetcode大佬Krahets的解法:循序遍历
时间复杂度,遍历一边数组:O(N)
空间复杂度,多用了一个res存储返回字符串:O(N)
(1)代码
class Solution(object): def convert(self, s, numRows): """ :type s: str :type numRows: int :rtype: str """ # 如果指定行数小于2,就是1,一行直接输出字符串即可 if numRows < 2: return s # 构建一个列表存储输出结果 # 保证列表长度和字符串长度相同即可,构建方法很多 res = ["" for _ in s] # 很重要,i 为索引下标,flag 是一个标识符,这里作者应用的很智慧 i, flag = 0, -1 # for循环便利输入字符串 for c in s: # 存储输出字符串 # 等价于 res[i] = res[i] + c res[i] += c # 很智慧,到这一步我们会发现索引下标i的界限[0, numRows - 1] # [0, numRows - 1]区间跨度也就是 numRows # 当到达边界的时候,flag = -flag 进行转向,保证i永远在[0, numRows - 1] if i == 0 or i == numRows - 1: # 转向 flag = -flag # 前进或后退 # 等价于 i = i + flag i += flag # 循环遍历字符串,直至字符串遍历完 # 利用join函数连接res列表里的每个元素 # 到此解题完毕 return "".join(res)
(2)提交结果
❝测试数据:1157个测试用例
运行时间:44 ms,击败92%
内存消耗: 13 MB,击败46%
❞
好奇心驱使,我看了看执行时间top1的代码,和Krahets大佬的代码是一样的。。。
我又看了看内存消耗最低的代码,我发现这就是我即将要和大家分享的第二位大佬的解题思路。
2.Leetcode大佬Zoffer的解法:周期打印
时间复杂度:O(N)
空间复杂度:O(N)
(1)代码
class Solution(object): def convert(self, s, numRows): """ :type s: str :type numRows: int :rtype: str """ # 如果指定行数小于2,就是1,一行直接输出字符串即可 if numRows < 2: return s # 构建一个列表存储输出结果 rows = [""]*numRows # 我们按V字来看这个题目 # 一个V包含的字符个数就是 最高点和最低点以及中间两段 # 和行数关联,numRows行每一竖条应该有numRows个字符,去除头尾就是(numRows-2) # 故一个V包含字符数为:2+2*(numRows - 2) = 2*numRows - 2 n = 2*numRows - 2 # 遍历字符串,枚举,直接获取到索引和索引对应的字符 for i,char in enumerate(s): # % 取余,控制x在周期内[0, n] x = i % n # 这里很智慧的就是利用min函数来自动转向 # 当是下去的一笔时,x总小于n-x # 当是上去的一笔时,n-x总小于x rows[min(x, n-x)] += char # 利用join函数连接res列表里的每个元素 # 到此解题完毕 return "".join(rows)
(2)提交结果
❝测试数据:1157个测试用例
运行时间:52 ms,击败75%
内存消耗: 13 MB,击败42%
提交了很多次,也没有出现内存消耗很少的情况,所以这个提交检测排名还是有一定的偶然性的~不过,重要的是理解解题思路,加油。
❞
五、疑惑
今日分享:如果你处于和我一样“比上不足,比下有余”的地方,我建议你两点:
1、承认。有人比我们优秀是正常的,没有人比我们优秀这才是坏事,如果你发现,你周围的人都不如你优秀,那说明,你现在的环境已经不适合你发展了,当然你可以跳出当前环境或者接触新环境带动当前环境(前者是技术人,后者是领导者)
2、做自己。完全没必要去和不优秀的人比较,也没必要和特别优秀的人较劲,做好自己,人生漫漫长路,你得一点一点积累,不因小事而停顿,不因大事而搓返。
六、结语
思想很复杂, 实现很有趣, 只要不放弃, 终有成名日。---《老表打油诗》