6. ZigZag Conversion( Z 字形变换)两种解题方法(C++ & 注释)
6. ZigZag Conversion( Z 字形变换)
1. 题目描述
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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
2. Sort by Row(按行排序)
2.1 解题思路
按行排序的思路其实非常简单易懂:我们可以看到Zigzag后的字符串其实是元字符串从第一个字符开始,先竖向往下排序,当行数到达第numRows - 1行后,后退一行,并向上开始排序,之后行数到达第0行后,前进一行,重新开始向下开始排序,这题思路如下图所示:
理解上述思路以后,代码就显得非常简单了,并不难。
2.2 实例代码
class Solution { public: string convert(string s, int numRows) { if (numRows <= 1) return s; vector<string> zigzag(min(numRows, static_cast<int>(s.size()))); // 需考虑到s的长度为零的情况 int curRow = 0; bool goDown = false; for (int i = 0; i < s.size(); i++) { zigzag[curRow] += s[i]; // 添加当前行的字符 if (curRow == 0 || curRow == numRows - 1) goDown = !goDown; // 如果当前行位于收尾需要转换方向 curRow += goDown ? 1 : -1; // goDown为真,访问下一行;反之,访问上一行 } string ans(""); for (string& str : zigzag) ans += str; return ans; } };
3. Visit by Row(按行访问)
3.1 解题思路
除了按照行排序,那我们能不能直接计算出竖行和斜行分别对应原字符串序号的规律呢?答案当然是OK哒,我们先来看看几个例子,然后从里面总结出规律:
从图中,我们可以看到斜行的字符个数与numRows的关系为:numRows > 2 ? numRows - 2 : 0;接着,我们可以观察到首行尾行和中间行有着不同的规律,我们以numRows = 3为例。
1)首行和尾行:
首行的字符为:a, e, i,对应序号0, 1, 8;尾行字符为:c, g, k,对应序号2, 6, 10。我们可以发现每个序号的差值刚好为4,即首行和尾行的上一个字符与下一个字符的序号差值为2 * numRows - 2,这个公式怎么得到的呢?我们可以观察一下原字符串,a走到下一个字符e需要跳过那些字符呢?首先我们要走到c,也就是走到竖行字符的最后一个,走过的字符数为:numRows - 1,然后我们需要走完斜行的所有字符,即numRows - 2个字符,然后再走一步,达到e字符,所以一共跳过的序号为:numRows - 1 + numRows - 2 + 1 = 2 * numRows - 2;
2)中间行
中间行的首字符序号为1 ~ numRows - 1,也就是第一个竖行除去首尾的字符。之后先访问斜行对称的字符,比如numRows = 4时,bc对应ef,先访问b然后访问斜行最后一个字符f,刚好是竖行中间与斜行放在一起,两者对称位置上的字符。然后访问下一个竖行对应位置的字符,之后重复上述动作直到序号越界就停止。我们观察发现从竖行到下一个竖行的移动距离和上面首尾行的是一样的,都为2 * numRows - 2。但是从竖行的字符到对应斜行的字符距离为numRows - (i + 1) + numRows - 2 - i + 1,i为第一个竖行字符的序号。
那这个距离公式怎么得到的呢?还是numRows = 3时,首先从b到d,b的序号为1,b之前(包含自己)一共有i + 1个字符,所以需要跳过b之后的字符数为numRows - (i + 1)个,然后我们要跳过斜行的字符,斜行有numRows - 2个字符,我们需要计算与竖行对称的字符之前有多少个字符,只需要用斜行的字符个数减去i所在竖行后面的字符数(除去首尾)即numRows - 2 - i + 1个
最后我们只需遍历0 ~ numRows - 1序号的字符就可以得到答案了。其实代码里面两个函数可以合成到一起,毕竟跳到下一个竖行字符,首尾和中间行都是2 * numRows - 2,大家可以自己尝试合并一下呢。
3.2 实例代码
class Solution { public: string convert(string s, int numRows) { if (numRows <= 1) return s; string ans(""); for (int i = 0; i < numRows; i++) { if (i == 0 || i == numRows - 1) addCharacterAtBoundary(s, ans, numRows, i); // 添加收尾两行字符 else addCharaceterBetween(s, ans, numRows, i); // 添加中间行字符 } return ans; } void addCharacterAtBoundary(string& s, string& ans, int numRows, int i) { int jumpTo = 2 * numRows - 2; // 跳到下一个竖边的对应字符 while (i < s.size()) { ans.push_back(s[i]); i += jumpTo; } } void addCharaceterBetween(string& s, string& ans, int numRows, int i) { int numberOfZigzag = numRows - 2 - i + 1, // 计算中间斜边上字符的总数 len = s.size(), jumpToZigzag = numRows - (i + 1) + numberOfZigzag, // 跳到下一个斜边的对应字符 jumpToNext = 2 * numRows - 2; while (i < len) { //cout << i << jumpToZigzag << " "; ans.push_back(s[i]); if (i + jumpToZigzag >= len) break; ans.push_back(s[i + jumpToZigzag]); i += jumpToNext; } } };
如果大家有任何的问题,欢迎在下方留言,我看到以后会及时回复大家哒~
- vim中代码注释与取消的两种方法
- leetCode 103.Binary Tree Zigzag Level Order Traversal (二叉树Z字形水平序) 解题思路和方法
- leetcode解题之09#Palindrome Number Java版 两种方法实现
- 解题常用的两种将输入序列中的字符表示的数转化成对应进制的数值的方法
- 计算斐波那契数列,两种方法,打开注释掉的语句你会感受到算法的力量
- leetCode 6. ZigZag Conversion(Z形变换) 解题思路及方法
- Eclipse中注释方法操作(两种)
- 用java语言,操作给定的二叉树,将其变换为源二叉树的镜像(递归和循环两种方法)
- 19. Remove Nth Node From End of List(删除链表的倒数第N个节点)两种解法(C++ & 注释)
- css+div及javascript应用---------鼠标经过时图片变换的两种方法
- Laravel获取数据表字段注释的两种方法
- 程序员面试金典——解题总结: 9.18高难度题 18.10给定两个字典里的单词,长度相等。编写一个方法,将一个单词变换成另一个单词,一次只改动一个字母。
- leetCode 103.Binary Tree Zigzag Level Order Traversal (二叉树Z字形水平序) 解题思路和方法
- 48. Rotate Image(旋转图像)两种解法(C++ & 注释)
- leetcode解题之14# Longest Common Prefix Java版 两种方法实现
- 用深搜和广搜两种方法解题---黑色格子
- 46. Permutations(全排列)两种解法(C++ & 注释)
- elementUI Vue 单个按钮显示和隐藏的变换功能(两种方法)
- 鼠标经过图片时变换的两种方法--css+div及javascript应用
- 中国大学MOOC浙大数据结构04-树6 Complete Binary Search Tree (30分) 两种解题方法(2)