z-字形变换
题目
将一个给定字符串 s 根据给定的行数 numRows, 以从上往下, 从左到右进行 Z 字形排列. 比如输入字符串为 "PAYPALISHIRING" 行数为 3 时, 排列如下:
P   A   H   N
A P L S I I G
Y   I   R
之后, 你的输出需要从左往右逐行读取, 产生出一个新的字符串, 比如: "PAHNAPLSIIGYIR".
提示:
1 <= s.length <= 1000s由英文字母(小写和大写),','和'.'组成1 <= numRows <= 1000
示例
输入: s = "PAYPALISHIRING", numRows = 4
输出: "PINALSIGYAHRPI"
解释:
P     I     N
A   L S   I G
Y A   H R
P     I
题解
以 s = "PAYPALISHIRING", numRows = 4 为例, 把 Z 字形数字转换成索引排列, 然后我们来找规律.
0       6        12
1    5  7     11 13
2  4    8  10
3       9
我们从第一排可以看到循环的数字跟 6 有关, 因此可以以 6 为突破口试试:
- 第一排 
0 % 6 = 0;6 % 6 = 0;12 % 6 = 0. 可以看到取余都是0, 即可根据余数判断这几个字母是第一排. - 第二排 
1 % 6 = 1;5 % 6 = 5;7 % 6 = 1;11 % 6 = 5;13 % 6 = 1. 可以看到余数都是1或者5, 对于5, 可以通过6 - 5变成1. - 第三排 
2 % 6 = 2;4 % 6 = 4;8 % 6 = 2;10 % 6 = 4. 可以看到余数都是2或者4, 对于4, 可以通过6 - 4变成2. - 第四排 
3 % 6 = 3;9 % 6 = 3. 可以看到取余都是3, 即可根据余数判断这几个字母都是第三排. 
当然这个 6 是怎么来的呢? 即 (numRows - 1) * 2.
- JavaScript
 - Rust
 
/**
 * @param {string} s
 * @param {number} numRows
 * @return {string}
 */
var convert = function (s, numRows) {
  // 如果 numRows 比 2 小, 是没法变成 Z 型的, 直接返回 s 即可
  if (numRows < 2) return s
  const n = s.length
  // 初始化一个数组, 数组长度为 numRows
  const res = Array(numRows).fill('')
  // 循环, 也就是示例中的 6
  const cycle = (numRows - 1) * 2
  for (let i = 0; i < n; i++) {
    // 计算余数
    const carry = i % cycle
    // 计算索引, 如果余数小于 numRows, 那就用这个余数即可, 否则用循环数减去该余数
    const idx = carry < numRows ? carry : cycle - carry
    res[idx] += s[i]
  }
  // 最后把数组合并成字符串即可
  return res.join('')
}
pub fn convert(s: String, num_rows: i32) -> String {
    if num_rows < 2 {
        return s;
    }
    let n = s.len();
    let vec = s
        .chars()
        .collect::<Vec<char>>()
        .iter()
        .map(|&x| x.to_string())
        .collect::<Vec<String>>();
    let mut arr = vec![String::from(""); num_rows as usize];
    let cycle = (num_rows - 1) * 2;
    for i in 0..n {
        let carry = (i as i32) % cycle;
        let idx = if carry < num_rows {
            carry
        } else {
            cycle - carry
        };
        // impl Add<&str> for String {
        //     type Output = String;
        //     #[inline]
        //     fn add(mut self, other: &str) -> String {
        //         self.push_str(other);
        //         self
        //     }
        // }
        // 注意字符串加法必须是 String + &str
        arr[idx as usize] += &vec[i];
    }
    arr.join("")
}