The ZigZag Conversion Problem ZigZag 转换问题
(leetcode.com/problems/zi...).
今天的算法是 ZigZag 转换问题。给你一个字符串和一些行。这个想法是,给定的字符串以锯齿形模式写入,并且该函数应该返回该字符串在逐行读取时的读取结果。
我认为这个问题的写法特别令人困惑,所以让我们看一个例子。
如果给定的字符串是"ALGORITHMOFTHEDAY",并且行数是 4,则它看起来像这样:
css
A T H
L I H T E
G R M F D Y
O O A
逐行读取,您会得到字符串"ATHLIHTEGRMFDYOOA",这将是该函数的输出。
我认为这是一种分解示例可以帮助您找到解决方案的算法。因此,我将首先通过一个示例并考虑如何解决该问题,然后我将讨论代码。
解决锯齿形调整浪问题
假设给定字符串"ABCDEFGH",锯齿形的行数为 3。写下来,看起来像这样:
去掉所有字母,我们有三行,可以将其视为三个数组。
现在,为了构建这个锯齿形单词,我们可以在给定的字符串中逐个字母。从前三个字母"ABC"开始,我们可以将它们放在三行(或数组)的开头。一旦我们到达底行,我们就知道我们无法在该方向添加更多字母,因此我们必须开始反转方向。
我们将在这个相反的方向上添加"D"和"E",但是一旦我们到达第一行,我们再次知道我们不能继续这个方向。
我们可以继续做同样的事情,沿一个方向添加字母,直到到达最后一行,然后反转方向,直到添加了字符串的所有字母。
去掉数组的行(本质上是将这些数组转换为字符串),我们得到三个字符串。
将它们逐行相加,我们得到结果:"AEBDFHCG"。
这个例子展示了我将如何解决这个问题:为给定的行构建相同数量的数组,将给定字符串的字母添加到每个数组,直到到达最后一个数组,然后反转方向。一旦我们到达第一个数组,再次反转方向。继续这样做,直到我们用完输入字符串中的字母为止。最后,将各个数组的字母连接起来形成字符串,然后将这些字符串连接起来形成一个最终字符串。
Coding the ZigZag Problem 编写 ZigZag 问题的代码
现在我们已经完成了一个示例,我们可以继续编写解决方案。在该问题中,我们给出了字符串 s
和一些行 numRows
。要做的第一件事是考虑基本情况:如果只有一行,那么甚至不可能出现锯齿形,因此我们可以返回字符串。另一种基本情况是,如果字符串比给定的行数短,在这种情况下,锯齿形也不可能出现,因此我们可以再次返回字符串。
javascript
function convert(s, numRows) {
if (numRows === 1 || s.length < numRows) {
return s;
}
//...
}
现在我们需要构建一些变量。首先是一个存储其他数组 rows
的数组。 rows
中的每个数组将存储一行之字形图案。我们还需要为当前所在行构建一个计数器 currentRow
,该计数器从 0 开始。我们需要一个等于布尔值的变量,该变量表示我们是否正在切换方向 < b3>。最后,我们需要创建一个最后返回的空字符串 result
。
ini
function convert(s, numRows) {
if (numRows === 1 || s.length < numRows) {
return s;
}
let rows = [];
let currentRow = 0;
let reverse = false;
let result = "";
//...
}
我们现在想要构建 numRows
中给出的行数。为此,我们可以创建一个 for 循环,从 0 到 numRows
,并每次构建一个新的空白数组。
ini
function convert(s, numRows) {
if (numRows === 1 || s.length < numRows) {
return s;
}
let rows = [];
let currentRow = 0;
let reverse = false;
let result = "";
for (let i = 0; i < numRows; i++) {
rows[i] = [];
}
//...
}
现在,我们要遍历"s"中的每个字符,并将其推送到不同的行,直到完成每个字母。因此,这是使用 for 循环的好地方,从第一个字母(在索引 0 处)开始,直到最后一个字母(在 s.length
处)。
在 for 循环内,我们希望将此字母 ( s[i]
) 推送到基于 currentRow
的行。如果我们向下走, currentRow
就会变大;如果我们反转方向, currentRow
就会变小------所以我们应该在这里有一个条件语句。如果 reverse
为 true,则 currentRow
应该变小;否则, currentRow
应该变大。
考虑一下之前的示例, reverse
最初是 false
,因此 currentRow
计数继续变大。一旦我们到达底行, reverse
就被设置为等于 true
,此时 currentRow
计数继续变小。
因此,在 for 循环中,我们可以检查 reverse
是 true 还是 false。如果为 false,那么我们可以增加 currentRow
。否则,我们可以递减 currentRow
。
ini
function convert(s, numRows) {
if (numRows === 1 || s.length < numRows) {
return s;
}
let rows = [];
let currentRow = 0;
let reverse = false;
let result = "";
for (let i = 0; i < numRows; i++) {
rows[i] = [];
}
for (let i = 0; i < s.length; i++) {
rows[currentRow].push(s[i]);
if (reverse === false) {
currentRow++;
} else {
currentRow--;
}
//...
}
//...
}
我们在 for 循环中要做的最后一件事是检查我们是在最后一行还是在第一行。在这两种情况下,我们都希望朝着与刚才相反的方向前进,因此我们可以将 reverse
设置为等于 !reverse
。
ini
function convert(s, numRows) {
if (numRows === 1 || s.length < numRows) {
return s;
}
let rows = [];
let currentRow = 0;
let reverse = false;
let result = "";
for (let i = 0; i < numRows; i++) {
rows[i] = [];
}
for (let i = 0; i < s.length; i++) {
rows[currentRow].push(s[i]);
if (reverse === false) {
currentRow++;
} else {
currentRow--;
}
if (currentRow === numRows - 1 || currentRow === 0) {
reverse = !reverse;
}
}
//...
}
一旦 for 循环执行完毕,我们将得到多个数组。我们希望将每个数组转换为字符串,然后将这些字符串相互添加。
为此,我们可以在 rows
中的每一行调用 .forEach()
。对于每一行,我们可以使用 .join()
将其转换为字符串。然后我们可以将每个字符串添加到 result
中。最后,在 forEach
方法之外,我们可以返回结果。
ini
function convert(s, numRows) {
if (numRows === 1 || s.length < numRows) {
return s;
}
let rows = [];
let currentRow = 0;
let reverse = false;
let result = "";
for (let i = 0; i < numRows; i++) {
rows[i] = [];
}
for (let i = 0; i < s.length; i++) {
rows[currentRow].push(s[i]);
if (reverse === false) {
currentRow++;
} else {
currentRow--;
}
if (currentRow === numRows - 1 || currentRow === 0) {
reverse = !reverse;
}
}
rows.forEach((row) => {
result += row.join("");
});
return result;
}
如果您对如何解决此问题有任何疑问或其他想法,请在评论中告诉我!