LeetCode6-Z 字形变换

LeetCode6-Z 字形变换

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:

L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);
示例 1:

输入: s = “LEETCODEISHIRING”, numRows = 3
输出: “LCIRETOESIIGEDHN”
示例 2:

输入: s = “LEETCODEISHIRING”, numRows = 4
输出: “LDREOEIIECIHNTSG”
解释:

L D R
E O E I I
E C I H N
T S G

一、思路

(一)直觉想法

题目给出字符串和每行字符个数,整个Z字形变换就已经完成了,同一行的字符在字符串中的间隔应该是一样的(除了最后的字符)

1、例子

输入: s = “LEETCODEISHIRING”, numRows = 3
第一个字符s[0]下面还有2个字符(s[1],s[2]),再加上Z字形中间的1(s[3])个,下一个字符应该是s[4]

2、推广

输入:s,numRows=m,假定字符串长度为n

那么整个Z字形组成的矩阵应有:
m行k列,将含有m个字符的列称为满列,设满列有k1个,令k2=k-k1

两个满列之间间隔:m-2列,且满列之间的列,每列只有1个字符,且:n = k1*m+k2

  • 第一(m)行的字符:每个字符在字符串中的间隔是:(m-1)+(m-2)+1
    简化为: 2 ( m − 1 ) 2(m-1) 2(m1)

  • 第二行的字符:嗯,遇到问题了,不同的字符,间隔可能不一样的
    实际上呢,这是由于上下不对称造成的,需要分情况讨论,不过也不复杂,就只有两类:
    (1)第奇数次寻找下一个字符时,间隔:(m-2)+(m-3)+1,简化为: 2 ( m − 2 ) 2(m-2) 2(m2)
    (2)第偶数次寻找下一个字符时,间隔:2

  • 第k(k不等于1或者m)行的字符:同样要分情况讨论:
    (1)第奇数次寻找下一个字符时,间隔:(m-k)+(m-k-1)+1,简化为: 2 ( m − k ) 2(m-k) 2(mk)
    (2)第偶数次寻找下一个字符时,直接想不好想出来,反过来想,这个字符位于两个满列之间,行数是第k行,如果倒转过来,将第m行视为第一行,那么第k行则被视为第m-k+1行,那么间隔为:(m-(m-k+1))+(k-2)+1,这里的(k-2)是因为第一个数在第一项已经计算过了,不再重复记录,简化为: 2 ( k − 1 ) 2(k-1) 2(k1)

这么一来所有的情况都考虑到了

C++代码如下:

class Solution {
public:
	string convert(string s, int numRows) {
		string s_z;
		int high = s.size() - 1, k = 0;
		int len = high + 1;

		if (len == 1 || numRows == 1) {
			return s;
		}
		s_z.reserve(len);
		// 获取第一行字符
		for (int i = 0; i <= high; ) {
			s_z[k++] = s[i];
			i = i + 2 * (numRows - 1);
		}

		// i表示行数,i1的初值表示,第i行的第一个字符
		for (int i = 2; i < numRows; i++) {
			int i1 = i - 1;
			for (int j = 1; i1 <= high; j++) {
				if (j % 2 != 0) {
					s_z[k++] = s[i1];
					i1 = i1 + 2 * (numRows - i);
				}
				else {
					s_z[k++] = s[i1];
					i1 = i1 + 2 * (i - 1);
				}
			}
		}

		// 获取最后一行的字符
		for (int i = numRows - 1; i <= high; ) {
			s_z[k++] = s[i];
			i = i + 2 * (numRows - 1);
		}
		s_z[k] = '\0';
		return s_z;
	}
};

执行效率:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值