leetcode之路006 ZigZag Conversion


题目大意:给定一个以之字形形式存储的字符串,并且给定之字形的行数,如下,行数为3,给定的string为"PAYPALISHIRING"

P   A   H   N
A P L S I I G
Y   I   R
然后现在一行一行的读取其值, 得到 "PAHNAPLSIIGYIR"

现在给定一个字符串s和行数numRows,输出其转换后的字符串。

首先考虑边界条件:s的长度小于行数,则直接输出s;numRows为1,也直接输出s。


思路:

1、对于行数为n时,可以看出每隔2n-2为一个周期ts,即上图P到A相差2n-2个。下面将以周期进行处理。

因此根据规律,第一行字符在s中的下标是一个等差数列,即0,2n-2,2*(2n-2),3*(2n-2),4*(2n-2)...

对于最后一行,在s中的下标也是一个等差数列,即(n-1),(n-1)+(2n-2),(n-1)+2*(2n-2),(n-1)+3(2n-2)...

2、对于中间行,因为在一个周期ts中出现了两次,而且出现的位置有一定的关系,设两次的位置分别为i1,i2,关系即为i1%ts+i2%ts=ts。

3、对于上述两点,可以归并到一起处理。当求出的i1==i2时,此时即为第一行和最后一行情况。


下面是ac的代码,运行时间是16ms:

class Solution {
public:
    string convert(string s, int numRows) {
        int m=0,i1=0,i2=0,j=0;
		string resu;
		if(s.length()<=numRows)
			return s;
		if(numRows==1)
			return s;
		int ts=(2*numRows-2);
		for(m=0;m<numRows;++m)
		{
			j=0;
			i1=j+m%ts;
			i2=j+(ts-m)%ts;
			while(i2<s.length())
			{
				if(i1!=i2)
				{
					resu+=s[i1];
					resu+=s[i2];
				}	
				else
					resu+=s[i1];
				j+=ts;
				i1=j+m%ts;
				i2=j+(ts-m)%ts;
			}
			if(i1<s.length())
				resu+=s[i1];
		}
		return resu;
    }
};

此算法是O(n)的,外层执行次数为行数numRows,每次while需访问每一行的每个元素一次,总次数为s.length(),因此复杂度为O(n)。因此代码的运行时间,已经是最低了。并且没有使用大量的空间,唯一的缺点是,有点难于理解,不够简洁。

下面是讨论区的最简单的实现,用了字符串数组来记录每行的字符,最后再合并起来:

string convert(string s, int nRows) {

    if (nRows <= 1)
        return s;
    const int len = (int)s.length();
    string *str = new string[nRows];
    int row = 0, step = 1;
    for (int i = 0; i < len; ++i)
    {
        str[row].push_back(s[i]);

        if (row == 0)
            step = 1;
        else if (row == nRows - 1)
            step = -1;

        row += step;
    }
    s.clear();
    for (int j = 0; j < nRows; ++j)
    {
        s.append(str[j]);
    }
    delete[] str;
    return s;
}


2016.09.04更新 JAVA代码:

public class Solution {
    	public String convert(String s, int numRows) {
        if(s == null || numRows < 2){
            return s;
        }
        char[] str = new char[s.length()];
        int len = s.length();
        int index = 0;
        for(int i = 0; i < numRows; i++) {
            for(int j = i; j < len; j += (2 * numRows - 2) ) {
                str[index++] = s.charAt(j);
                int mid = j + (2 * numRows - 2 -2 *i); 
                if(i != 0 && mid > j && mid < len) {
                    str[index++] = s.charAt(mid);
                }
            }
        }
        return String.valueOf(str);
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值