您的位置:首页 > 其它

[LeetCode]#6 ZigZag Conversion

2015-07-21 16:59 274 查看
一、题目

Thestring[code]"PAYPALISHIRING"
iswritteninazigzagpatternonagivennumberofrowslikethis:(youmaywanttodisplaythispatterninafixedfontforbetterlegibility)[/code]
PAHN
APLSIIG
YIR

Andthenreadlinebyline:[code]"PAHNAPLSIIGYIR"


Writethecodethatwilltakeastringandmakethisconversiongivenanumberofrows:

stringconvert(stringtext,intnRows);

convert("PAYPALISHIRING",3)
shouldreturn
"PAHNAPLSIIGYIR"
.[/code]

二、解析

这题是一道找规律的数学题,找到规律后并不难。是要将原字符串按照Z字型排好后,从上到下以此输出元素。直接拿例子来说吧。

先说一下给的例子,写出Z字型的字母和下标,如下图所示。根据下标我们可以看到,其实无论字符串内容是什么,Z型的下标其实都是固定的。因此我们的任务转化成为:找到字符长度和Z层数之间的数学关系。也就是说,以3层为例,我们要输出的顺序是048121357911132610这些位置上对应的字符。

P:0A:4H:8N:12
A:1P:3L:5S:7I:9I:11G:13
Y:2I:6R:10

再画出一个5层的例子,方便对比:
0   8  16
1 791517
2 6 101418
35  111319
4   1220

完整的Z字型是有规律可循的,比如5层中,后面所有的数字都在重复0-8的过程,所以我们来看看哪里可以被我们所用:

1.3层中,第一行为04,5层中,第一行为08,这里我们发现,差值delta=2*(层数-1)。例如在5层中,第0行相同位置0和8相差8,第1行相同位置19相差8。好了,这里我们得打了第一个有用规则。继续往下看。

2.3层中,最后一行为2610,5层中,最后一行为41220,相差为8上面已经得到。统筹的看第一行与最后一行,我们发现这两行的元素是比较整齐的,中间没有插入的元素。所有这两行在做处理的时候,应该归为一类。

3.下面我们看最左边一行,都是0123..代表的是第几层,ok这个很容易

4.剩下最后的也是最复杂的,中间部分。拿5层中第1行为例:1791517,这里面其实有两部分内容。第一部分同第一行和最后一行一样,是比较整洁的元素,如1917,他们之间相差都是8.第二部分就是多出来的7和15,如何求的他们呢?这时我们看第一行1和7相差6,第二行2和6相差4,第三行3和5相差2,这里我们就找到了规律,即:7=1+6=1+2*3,6=2+4=2+2*2,5=3+2=3+2*1。这里,等号左边是我们要通过公式得到的,等号右边第一项是行数,第二项2*n,n就是总行数-当前行数。7(要求的)=1(目前是第一行)+2*3(总行数为4,从0开始-1当前行)。

OK到这里,我们已经找到了所有的规律,总结如下:

1.相同位置差距delta为2*(层数-1)

2.第一行和最后一行无间隔元素

3.中间元素为:当前行+2*(总行数-当前层行)

三、代码:

classSolution:
#@param{string}s
#@param{integer}numRows
#@return{string}
defconvert(self,s,numRows):
length=len(s)
delta=2*(numRows-1)
zigzag_pos=[]
ifnumRows==1orlength<=numRows:
returns
else:
#cratethezigzagpostoindicatetheorderofs
foriinrange(numRows):
forjinrange(i,length,delta):
zigzag_pos.append(j)
if(i!=0)and(i!=numRows-1)and(j+(numRows-i-1)*2<length):
zigzag_pos.append(j+(numRows-i-1)*2)

zigzag_str=[]
foriinzigzag_pos:
zigzag_str.append(s[i])
return''.join(zigzag_str)


这里解释一下else以后的那部分,是最主要的地方。

首先,我们用了两层循环i和j。i用来表示哪一层,j用来表示i层中的第几个元素。我们注意到在j循环中,用到了i,length,delta的写法,这样的意思是,从i开始,到length结束,每间隔delta是一个j。其实原本程序是这么写的,下面这个可能看的更清楚一些:

foriinrange(numRows):
forjinrange(i,length,delta):
if(i==0)or(i==numRows-1):
zigzag_pos.append(j)
else:
7zigzag_pos.append(j)
if(j+(numRows-i-1)*2<length):
zigzag_pos.append(j+(numRows-i-1)*2)


这个是不是更容易看懂些呢?

j循环中,第一个

if(i==0)or(i==numRows-1),是用来处理第一行和最后一行,比较干净的元素的。意思就是,这两行的元素,直接将j添加进list。

else就是中间元素。else后第一句zigzag_pos.append(j),是用来添加那些第一类元素,也是比较干净的,例如1916这种

第二句if(j+(numRows-i-1)*2<length),是用来记录中间元素,仔细看的话就是我们刚才推到出的公式。

由于if..else..中都有一句zigzag_pos.append(j),所以我将他提出来,改了一下判读条件,就成了第一份代码的样子。


三、总结
1.写代码之前一定要想清楚。像这种简单的数学题,一定要理清思路。不能靠乱改代码想着凑出一个正确答案,这样是很浪费时间的。
2.你们可能看到了我把第5题回文给跳过去了,只是因为耽误的时间有点多,想着先练一练手。另外我现在在放暑假哈哈哈,在家好幸福~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: