【咸鱼刷LeetCode-6】 Z 字形变换(中等)

将字符串按Z字型放入二维数组中,然后遍历按行遍历二维数组,得到结果。主要计算每个字符在数组中的位置即可。

行数就是方法第二个入参,数组列数的计算:每numRows + numRows - 2个数为一组,前numRows个数一列,后 numRows - 2个数,每个数一列;

不过这样的方式除了遍历字符串以外,还要额外扫描一次二维数组,增加耗时。


按照分组的思路(每numRows + numRows - 2个数为一组,前numRows个数一列,后 numRows - 2个数,每个数一列),最后输出的结果从前往后应该是(每组的第一个元素)+(每组第二个元素+每组倒数第一个元素) + (每组第三个元素+每组倒数第二个元素)....

 

按例子

1.字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

P   A   H   N
A P L S I I G
Y   I   R

即每个元素索引排列为

0          4          8           12
1    3    5    7    9    11    13
2          6          10

可分为batch = 4组。(0,1,2,3)(4,5,6,7)....(12,13)

2.

输入:s = "PAYPALISHIRING", numRows = 4时batch = 6
0              6               12    
1        5    7        11    13
2    4       8    10        
3             9

 

我们直接遍历二维数组的每一行,可以发现每个元素的index其实都是行、列和batch等参数的公式计算而得。

public String convert(String s, int numRows) {
		if (numRows == 1) {
			return s;
		}
		int batchs = s.length() / (numRows + numRows - 2);
		if (s.length() % (numRows + numRows - 2) != 0) {
			batchs++;
		}
		char[] z = new char[s.length()];
		int zIndex = 0;
		int batchNum = (numRows<<1) - 2;
		int index = 0;
		int indexZ = 0;
		for (int i = 0; i < numRows; i++) {
			for (int batch = 0; batch < batchs; batch++) {
				index = i + batch * batchNum;
				if (index < s.length()) {
					z[zIndex++] = s.charAt(index);
				} else {
					continue;
				}
				if (i > 0 && i < numRows - 1) {
                    // 中间行,每个batch之间都要多加一个数
					indexZ = batchNum * (batch + 1) - i;
					if (indexZ < s.length()) {
						z[zIndex++] = s.charAt(indexZ);
					} else {
						continue;
					}
				}
			}
		}
		return String.valueOf(z);
    }

优化:

我的代码里虽然是双循环,但是基本上每次都能遍历到一个元素,所以时间复杂度比O(n)大一点,因为else跳出循环的这块逻辑有问题,存在空循环的操作,所以每行开始的时候,能计算出本行的末尾的边界index,可以将时间优化到O(n)。

1。优化了else的逻辑之后,两个for循环遍历的次数达到了最少次数即numRows*batchs次,可是时间效率还是3ms;

2。又去掉了代码中的除法,取模和乘法计算,时间还是3ms。

将循环次数控制在最小并且减少乘除计算,并没有提升效率,然后看了下力扣上,这题最快的答案很少,对比了几个2ms的答案,感觉循环次数比我还多很多,百思不得其解,对比了半天我把代码中用到字符串长度的s.length()操作都替换掉了,一开始就int n = s.length();之后不再调用s的方法,发现!!!时间2ms了。。。。。。。。。。。

看来以后做题的过程中减少方法调用是一个提升速度的方法?

贴一个各种优化后的代码,时间为2ms和3ms,大概一半一半的几率(2ms的优化情况主要还是靠替换s.length(),其他修改基本没起作用)

class Solution {
    public String convert(String s, int numRows) {

		int n = s.length();
		if (n <= 2 || numRows == 1) {
			return s;
		}
		int batchNum = (numRows<<1) - 2;
		char[] z = new char[s.length()];
		int zIndex = 0;
		int index = 0;
		int indexZ = 0;
		int slengCopy = n;
		int bb = 0;//代替batch * batchNum
		for (int i = 0; i < numRows; i++) {
			slengCopy = n;
			bb = 0;
			for (; slengCopy > 0;) {
//				index = i + batch * batchNum;
				index = i + bb;
				if (index < n) {
					z[zIndex++] = s.charAt(index);
				} 
				if (i == numRows - 1 && (i + bb + batchNum) >= n) {
					break;
				}
				if (i > 0 && i < numRows - 1) {
					indexZ = batchNum + bb - i;
					if (indexZ < n) {
						z[zIndex++] = s.charAt(indexZ);
					} 
					if ((i + bb + batchNum) >= n) {
						break;
					}
				}
				slengCopy -= batchNum;
				bb += batchNum;
			}
		}
		return String.valueOf(z);
    
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值