1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
//! # 题目描述
//!
//! 将一个给定字符串 `s` 根据给定的行数 `numRows` ,以从上往下、从左到右进行 Z 字形排列。
//!
//! 比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:
//!
//! ```plain
//! P A H N
//! A P L S I I G
//! Y I R
//! ```
//!
//! 之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。
//!
//! 请你实现这个将字符串进行指定行数变换的函数:
//!
//! `string convert(string s, int numRows);`
//!
//! | 示例 1 |
//! | :-- |
//! | 输入:s = "PAYPALISHIRING", numRows = 3 |
//! | 输出:"PAHNAPLSIIGYIR" |
//!
//! | 示例 2 |
//! | :-- |
//! | 输入:s = "PAYPALISHIRING", numRows = 4 |
//! | 输出:"PINALSIGYAHRPI" |
//!
//! 解释:
//!
//! ```plain
//! P I N
//! A L S I G
//! Y A H R
//! P I
//! ```
//!
//! | 示例 3 |
//! | :-- |
//! | 输入: s = "A", numRows = 1 |
//! | 输出:"A" |
//!
//! 提示:
//!
//! - `1 <= s.length <= 1000`
//! - `s` 由英文字母(小写和大写)、',' 和 '.' 组成
//! - `1 <= numRows <= 1000`
//!
//! 来源:<https://leetcode.cn/problems/zigzag-conversion>
////////////////////////////////////////////////////////////////////////////////
/// 用于选择要执行的算法的 Enum
pub enum Algorithm {
/// 使用栈数组实现的字形变换
STACK = 0,
/// 使用二维数组实现的字形变换
MATRIX = 1,
}
/// Z 字形变换
///
/// 可以通过第三个参数选择要使用的算法
///
/// ### Arguments
/// * `s` - 等待变换的字符串
/// * `n_rows` - 变换后的行数
///
/// ```
/// use leetcode_rust::problems_cn::p000_0xx::p000_006::zigzag_conversion;
/// let mut result_value = zigzag_conversion(String::from("PAYPALISHIRING"), 1, None);
/// assert_eq!(result_value, String::from("PAYPALISHIRING"));
/// result_value = zigzag_conversion(String::from("PAYPALISHIRING"), 2, None);
/// assert_eq!(result_value, String::from("PYAIHRNAPLSIIG"));
/// result_value = zigzag_conversion(String::from("PAYPALISHIRING"), 3, None);
/// assert_eq!(result_value, String::from("PAHNAPLSIIGYIR"));
/// ```
pub fn zigzag_conversion(s: String, n_rows: i32, alg: Option<Algorithm>) -> String {
match alg.unwrap_or(Algorithm::STACK) {
Algorithm::MATRIX => convert_s1(s, n_rows as usize),
Algorithm::STACK => convert_s2(s, n_rows),
}
}
#[cfg(test)]
#[test]
fn test_zigzag_conversion() {
assert!(zigzag_conversion(String::from("PAPAL"), 1, None) == String::from("PAPAL"));
}
/// Z 字形变换(解法一)
///
/// 使用二维矩阵设计的算法
///
/// ### Arguments
/// * `s` - 等待变换的字符串
/// * `n_cols` - 变换后的列数
#[allow(unused_assignments)]
fn convert_s1(s: String, n_cols: usize) -> String {
let mut cur_row = 0u16;
let mut cur_col = 0u16;
let mut n_rows = 1;
// Considering max string length 1_000 ASCII characters, minimum 1 column,
// max row count would be 1_000.
let mut arr = vec![0u8; n_cols * 1000];
let mut direction = 0; // 0 for GO, 1 for TURN
let mut conv_idx = 0usize;
while conv_idx < s.len() {
// Set value of current pos
arr[cur_row as usize * n_cols + cur_col as usize] = s.as_bytes()[conv_idx];
conv_idx += 1;
// Calculate next coordinate and direction
if cur_col == 0 {
if n_cols > 1 {
if direction == 1 {
direction = 0;
}
cur_col += 1;
} else {
// Move to next row directly because only 1 column needed.
cur_row += 1;
n_rows += 1;
}
} else {
if direction == 0 {
if cur_col < n_cols as u16 - 1 {
// Only move to the right
cur_col += 1;
} else {
// Last position, change direction and move to next row
direction = 1;
cur_col -= 1;
cur_row += 1;
n_rows += 1;
}
} else {
// Move to left and below
cur_col -= 1;
cur_row += 1;
n_rows += 1;
}
}
}
conv_idx = 0;
let mut output = vec![0u8; s.len()];
cur_row = 0;
cur_col = 0;
let mut str_idx = 0;
while conv_idx < s.len() {
// Update value if not 0u8
str_idx = cur_row as usize * n_cols + cur_col as usize;
if arr[str_idx] != 0u8 {
output[conv_idx] = arr[str_idx];
conv_idx += 1;
}
// Change position.
if cur_row < n_rows - 1 {
cur_row += 1;
} else {
cur_row = 0;
cur_col += 1;
}
}
String::from_utf8(output.to_vec()).unwrap()
}
#[cfg(test)]
#[test]
fn test_conversion_s1() {
assert!(convert_s1(String::from("PAPAL"), 1) == String::from("PAPAL"));
}
/// Z 字形变换(解法二)
///
/// 使用栈数组设计的算法
///
/// ### Arguments
/// * `s` - 等待变换的字符串
/// * `n_rows` - 变换后的行数
fn convert_s2(s: String, num_rows: i32) -> String {
let mut rows = vec![String::new(); num_rows as usize];
let mut cur_row: i32 = 0;
let mut go_down: bool = true;
for val in s.bytes() {
rows[cur_row as usize].push(val as char);
if !go_down && cur_row == 0 {
go_down = true;
} else if go_down && cur_row == num_rows - 1 {
go_down = false;
}
if go_down {
cur_row += 1;
} else {
cur_row -= 1;
}
cur_row = i32::min(num_rows - 1, cur_row);
cur_row = i32::max(0, cur_row);
}
rows.join("").to_string()
}
#[cfg(test)]
#[test]
fn test_conversion_s2() {
assert!(convert_s2(String::from("PAPAL"), 2) == String::from("PPLAA"));
}