Z字形变换

Z字形变换

  • 我的想法:找规律,看Z字形每个字符的索引在每一行上的规律,发现是有规律的。规律是有的,但是涉及到的i,j,k迭代的变量挺多的,自己没绕出来。我这里的方法对应下面官方讲解的第二个方法,可直接跳到这里。

碎碎念:看了官方对规律的描述,发现它的规律与我的规律的描述差距挺大的。我的规律是相对每一行来说的,而官方的规律总是相对numRows来描述的,所以更容易表达出来,因为numRows是个定值!而我找规律的基准是变化的,难怪没有绕出来,没法写出来…不过对于官方的规律,也不太容易想到吧。

方法一:按行排序

思路

从左向右迭代原始字符串,将每个字符都直接保存到其位于 Z 字形图案中的那一行。

算法

算法的关键在于如何找准每个字符应该存储到的行,我们观察示例可知,存储了一个字符后,要么就是在其下一行继续存储下一个字符,要么就是在其上一行继续存储下一个字符(注意,无须在意如何完全将那个Z字形打出来!关键是按照Z字形进行字符的重新保存!不要想偏了),所以我们可以使用变量curRow表示当前行,然后按照规则分别对curRow进行加1或减1操作。那么,这里的“规则”是怎样的呢?答:从第一行开始,存储完一个字符后每次都要进行加1操作,知道存储到了最后一行,然后开始进行减1操作。所以我们可以对第一行和最后一行设置一个goingDown标志;goingDownTrue时,表示改变当前行的操作是加1,goingDownFalse时,表示改变当前行的操作是减1。然后我们可以借助一个列表rows保存这numRows行的每行的字符串,当然,需要初始化这些字符串为空。此时,curRow就是rows的下标,所以Z字形的某行字符串就是rows[curRow]

def convert(s, numRows):
	if numRows == 1:
		return s

	rows = [''] * min(numRows, len(s)) # 相当于创建了一个“数组”

	curRow = 0

	'''
	 goingDown为True: curRow为前(numRows - 1)的情况
	 goingDown为False: curRow为最后一行numRows的情况
	'''
	goingDown = False

	for ch in s:
		rows[curRow] += ch
		if curRow == 0 or curRow == numRows - 1: 
			goingDown = (not goingDown)
		'''
		 goingDown为True时,下一当前行直接为(curRow + 1);
		 goingDown为False时,下一当前行需要跳转到前一行,所以(curRow - 1)
		'''
		curRow += (1 if goingDown == True else -1) 

	s_return = ''.join(rows)
	return s_return
	

print(convert("LEETCODEISHIRING", 3))

复杂度分析:
在这里插入图片描述

在这里插入图片描述

方法二:按行访问

思路

按照与逐行读取 Z 字形图案相同的顺序访问字符串。

算法

对于Z字形中每一行的第k个字符(k从0开始),有:

  • 第一行中的字符的索引:k * ( 2 * numRows - 2 )
  • 最后一行中的字符的索引:k * ( 2 * numRows - 2 ) + numRows - 1
  • 中间行 i 中的字符的索引:k * ( 2 * numRows - 2 ) + i 以及 ( k + 1 ) * ( 2 * numRows - 2 ) - i
def convert(s, numRows):
	if numRows == 1:
		return s

	s_return = ''
	length = len(s)
	cycleLen =  2 * numRows - 2

	for i in range(numRows):
		k = 0
		while k * cycleLen + i < length:
			if i == 0:
				s_return += s[k * cycleLen]
			elif i == numRows - 1:
				s_return += s[k * cycleLen + numRows - 1]
			else:
				s_return += s[k * cycleLen + i]
				x = ( k + 1 ) * cycleLen - i
				if x < length:
					s_return += s[x]
			k += 1
	return s_return
	
print(convert("PAYPALISHIRING", 3))

在这里插入图片描述

优化

观察上面的规律,可以发现:第一行 (i = 0) 以及最后一行 (i = numRows - 1) 中的字符的索引又可以归一成:k * ( 2 * numRows - 2 ) + i

def convert(s, numRows):
	if numRows == 1:
		return s

	s_return = ''
	length = len(s)
	cycleLen =  2 * numRows - 2

	for i in range(numRows):
		for k in range(0, length, cycleLen):
			if k + i < length:
				s_return += s[k+i]
				if (i != 0 and i != numRows-1 and k + cycleLen - i < length):
					s_return += s[k + cycleLen - i]
	return s_return
	
print(convert("PAYPALISHIRING", 3))

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值