[C++]ZigZag Conversion 之字形转换

leetcode 原题链接:https://leetcode.com/problems/zigzag-conversion/

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)

P   A   H   N
A P L S I I G
Y   I   R
And then read line by line:  "PAHNAPLSIIGYIR"

Write the code that will take a string and make this conversion given a number of rows:

string convert(string text, int nRows);
convert("PAYPALISHIRING", 3)  should return  "PAHNAPLSIIGYIR" .

简要翻译:对字符串"PAYPALISHIRING"进行给定行数的之字形转换。

例如对于字符串"PAYPALISHIRING"而言,给定行数为3,则其之字形为

P   A   H   N
A P L S I I G
Y   I   R
然后,逐行读取字符拼接成字符串得到 "PAHNAPLSIIGYIR"

若给定行数为4,则其之字形为

P I N

A L S I G

Y A H R

P I

因此,转换后的字符串为PINALSIGYAHRPI


简要分析:

根据题目意思,我们可以很容易的了解到这道题要我们做的事情。

思路(1)

最直观、最好理解的做法就是生成一个矩阵,存放字符的位置。手动怎么画,我们就怎么生成这个举证

例如,我们有个长度为13的字符串,给定的行数为3,则每个字符在矩阵中的位置如下:

0 4 8 12

1 3 5 7 9 11

2 6 10

其余空的位置为设置为-1;

实现代码:

string convert(string s, int numRows)
	{
		if (s.size() <= 1 || numRows <= 1)
			return s;
		vector<vector<int> > matrix;
		int index = 0;
		vector<int> intVector;
		for (int i = 0; i < (s.size()+1) / 2; i++)
		{
			intVector.clear();

			if (i % (numRows-1) == 0)
			{
				for (int k = 0; k < numRows; k++)
				{
					intVector.push_back(index++);
				}
			} else
			{
				for (int k = 0; k < numRows; k++)
				{
					intVector.push_back(-1);
				}
				int pos = numRows - 1 - i % (numRows - 1);
				intVector[pos] = index++;
			}

			matrix.push_back(intVector);
		}

		string result = "";
		for (int i = 0; i < numRows; i++)
		{
			for (int j = 0; j < (s.size() + 1) / 2; j++)
			{
				cout << matrix[j][i] << "\t";
				
				if (matrix[j][i] >= 0 && matrix[j][i] < s.size())
				{
					result += s[matrix[j][i]];
				}
			}
			cout << endl;
		}
		/*cout << index << endl;
		cout << s.size() << endl;
		cout << result.size() << endl;*/
		return result;
	}

这个代码虽然答案是正确的,但是内存超限了。因为在实现的过程中,生成了一个矩阵去保存数据。空间复杂度是O(N* numRows)


这种解法不行,于是就开始思考是否可以从数学规律上去做,于是有了思路2

思路(2)根据下面这个数字矩阵,可以得到启发,即第一行相邻的两个数相差4,第二行相邻的两个数相差2,对应列为2+2(1和5对应0和4)。此处如果规律不明显,可以去绘制一个行数为4的矩阵。我们设定gap为第一行响铃数字差gap = 2*numRows-2,对应列之间数字差为n = gap, m = 0; 每一行的数字差与上一行的关系是n-2, m+2(此处的n, m表示上一行)

0<-  gap ->   4 8 12

1<-n-> 3 <-m->5 7 9 11

2 6 10

ps:我这里没有画特别清晰的图,如果有人有需要的话给我评论留言,我有空再过来补吧

具体实现代码:

string convert(string s, int numRows)
	{
		if (s.size() <= 1 || numRows <= 1)
			return s;
		string result = "";
		int gap = 2 * numRows - 2;
		int n = gap, m = 0;
		for (int i = 0; i < numRows; i++)
		{
			int j = i;
			while (j < s.size())
			{
				if (n > 0)
				{
					result += s[j];
					j += n;
				}
				
				if (j >= s.size())
					break;
				
				if (m > 0)
				{
					result += s[j];
					j += m;
				}
			}
			n -= 2;
			m += 2;
		}
			/*cout << s.size() << endl;
			cout << result.size() << endl;*/
		return result;
	}

这个实现的时间复杂度是o(N),空间复杂度O(1)

ps: 居然是目前(时间2015年8月25日21:23:16)leetcode上cpp提交的最快的代码,着实令我很震惊。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值