leetCode 6. ZigZag Conversion解题心得

最近正在学习Python,因为对语言的不熟练,所以打算刷题来使自己的语言掌握的更充分。在leetCode上看见了这么一道题

The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)

就是ZigZag 首先还是用图来说一下原理吧
首先就用简单的'0123456789012345678'来演示下


示意图.png

就是将数字按上图排放,以竖列形式拜访


读取示意图.png

读取的时候从左向右读所以最终读取出来的文字是"0482613579135726048"
读取方式也知道了,下面就该开始代码部分了。
首先我的思路就是按照图片方式,准备一个二维数组。
#这里是判断如果特殊情况,若给定行数过大或过下,直接做特殊处理
  if numRows == 2:
    array_1 = []
    array_2 = []
    for i in range(0,len(s)):
      if i % 2 == 0:
        array_1.append(s[i])
      else:
        array_2.append(s[i])
      str = ''.join(array_1)
      str += ''.join(array_2)
      return str
   elif numRows <= 1:
            return s
   elif numRows >= len(s):return s
列数为4时候快照.png
#首先根据上图中方框部分算出,当numRows = 4时候重复部分的数量为6,当numRows = 3时重复部分的字母数量为4,可以在纸上画出当numRows = 5时重复部分的字符数量为8,所以计算可得重复部分的数量随numRows变化的数量就是numRows + numRows - 2
#count 为剩余部分有多少个字符
  count = len(s) % (numRows + numRows - 2)
#index为总共有多少个块
  index = len(s) // (numRows + numRows - 2)
#i为这个块中有多少列观察可得,numRows 数量单独占一列,剩下的一个字符占一列,所以最终每个块中有1 + numRows - 2列
  i = index * (1 + numRows - 2)
#j为剩余部分字符减去列数后剩余数量+1列
  j = (count - numRows + 1) if count > numRows else 1
#total为总列数
  total = i + j
  array = []

接下来就该开始循环给对应字符放入数组中了

  for real_i in range(0,total):
#创建每列的数组
      real_array = []
#这个判断为判断是否为该块的第一列(第一列为字母数量为numRows,其他列数字母数量为1)
      if real_i % (numRows - 1) == 0:
#计算该块起始位置
        g = 2 * real_i
#循环添加字符进入数组
          for letter in range(g, g + numRows if g + numRows < len(s) else len(s)):
            real_array.append(s[letter])
      else:
#计算该列在该块中的位置
        real_index_i = real_i % (numRows - 1)
#计算这个字符处于这个数组中的第几个位置
        real_index_j = 2 * (real_i - real_index_i) + numRows
#取出字母
        letter = s[real_index_i + real_index_j - 1]
#循环向数组中加入字符
        for x in range(0,numRows):
          if x == (numRows - 1 - real_index_i):
            real_array.append(letter)
          else:
            real_array.append(' ')
#将这个数组加入总数组
      array.append(real_array)

这步做完了后,所有操作基本已经算是完成,这个已经算是完成一多半
最后就剩下拼凑字符串了

    str = ''
    i = 0
#取数组和平时遍历数组方式不太一样,外层的循环实际上是用来遍历每个数组的角标i的位置的
    while True:
      for sub_array in array:
        if len(sub_array) > i:
          real = sub_array[i]
#这个地方的判断是为了防止数字崩溃,因为当时用数字做的测试,将数字转换成字符
          if isinstance(real,int):
            str += '%d '%(real)
          else:
            str += real
#下面部分是为了方便打印出对应的格式的(真实提交测试时需要删去)
            str += ' '
        str += '\n'
        i += 1
      if i == numRows:
        break
    return str

经过测试提交,leetCode 给出的error是timeLimit,说明代码是可以正确计算出结果了,但是耗时非常长,复杂度至少是O(n*numRows),太复杂了,耗时主要是在从数组中取出对应字符的步骤,所以需要优化,最终决定优化的方式是将数组转化成字典,用key对应所在位置,直接优化复杂度为O(n3)

#首先是循环部分修改
    dic = {}
#real_i直接为所在位置的横坐标
    for real_i in range(0,total):
      if real_i % (numRows - 1) == 0:
        g = 2 * real_i
        for n in range(g, g + numRows if g + numRows < len(s) else len(s)):
#y为纵坐标
          index_y = letter - g
          index_x = real_i
          dic[index_x + index_y * (total)] = s[n]
      else:
        real_index_i = real_i % (numRows - 1)
        real_index_j = 2 * (real_i - real_index_i) + numRows
        letter = s[real_index_i + real_index_j - 1]
        index_y = numRows - 1 - real_index_i
        index_x = real_i
        dic[index_x + index_y * (total)] = letter

接下来就剩读取了,首先,现在key不是连续的,但是,咱们的位置排序却是从小到大排序的,所以,下一步的操作就是给key进行排序了,python有很强大的排序方法,就是sort

str = ''
i = 0
array = list(dic.keys())
array.sort()
for key in array:
  letter = dic[key]
  if isinstance(letter, int):
    str += '%d' % (letter)
  else:
    str += letter
return str

将修改后的代码重新提交测试,成功通过。应该还有更好的方法,就是直接计算出对应的角标位置,但是碍于时间有限,就先用这个方法偷偷懒啦

你可能感兴趣的:(leetCode 6. ZigZag Conversion解题心得)