atcoder/lib/string.rs
1//! 文字列と列に対するアルゴリズムです。
2
3use std::ops::{Bound, RangeBounds};
4
5/// ASCII 英字を `0..26` の添字へ変換します。
6///
7/// `char` と `u8` に実装されています。大文字・小文字の ASCII 英字にだけ使用してください。
8/// それ以外の値に対する変換結果は定義された用途を持ちません。
9pub trait AlphaExt {
10 /// ASCII 英字を大文字・小文字を区別しない添字へ変換します。
11 ///
12 /// `a` または `A` は `0`、`z` または `Z` は `25` です。呼び出し側は `self` が ASCII 英字であることを
13 /// 保証してください。
14 fn to_idx(self) -> usize;
15}
16
17impl AlphaExt for char {
18 fn to_idx(self) -> usize {
19 (self.to_ascii_lowercase() as u8 - b'a') as usize
20 }
21}
22
23impl AlphaExt for u8 {
24 fn to_idx(self) -> usize {
25 (self.to_ascii_lowercase() - b'a') as usize
26 }
27}
28
29/// `0..26` の添字を小文字の ASCII 英字へ変換します。
30///
31/// `usize` と `u8` に実装されています。`26` 以上の値を渡すと panic します。
32///
33/// # Examples
34///
35/// ```
36/// use atcoder::string::AlphaIndexExt;
37///
38/// assert_eq!(0_usize.to_alpha(), 'a');
39/// assert_eq!(25_u8.to_alpha(), 'z');
40/// ```
41pub trait AlphaIndexExt {
42 /// 小文字 ASCII 英字に対応する添字を返します。
43 ///
44 /// `0` は `a`、`25` は `z` です。`self` が `26` 以上の場合は panic します。
45 fn to_alpha(self) -> char;
46}
47
48impl AlphaIndexExt for usize {
49 fn to_alpha(self) -> char {
50 assert!(self < 26, "alphabet index out of range");
51 char::from(b'a' + self as u8)
52 }
53}
54
55impl AlphaIndexExt for u8 {
56 fn to_alpha(self) -> char {
57 assert!(self < 26, "alphabet index out of range");
58 char::from(b'a' + self)
59 }
60}
61
62/// Manacher 法で奇数長・偶数長の回文半径をまとめて返します。
63///
64/// 戻り値の長さは `2 * sequence.len() + 1` です。空の入力では `[1]` を返します。
65/// 偶数添字は要素間、奇数添字は元の要素を
66/// 中心とします。`radii[i]` は区切りを挿入した列上で中心自身を含む半径であり、対応する
67/// 元の回文長は `radii[i] - 1` です。元の列の添字における回文の開始位置は、中心 `i` と半径 `r`
68/// から `(i + 1 - r) / 2` で求められます。`N = sequence.len()` とすると、計算量と追加メモリは `O(N)` です。
69///
70/// # Examples
71///
72/// ```
73/// use atcoder::string::manacher;
74///
75/// let radii = manacher(&['a', 'b', 'b', 'a']);
76/// assert_eq!(radii[4] - 1, 4);
77/// ```
78pub fn manacher<T: Eq + Clone>(sequence: &[T]) -> Vec<usize> {
79 let mut separated = Vec::with_capacity(2 * sequence.len() + 1);
80 for value in sequence {
81 separated.push(None);
82 separated.push(Some(value.clone()));
83 }
84 separated.push(None);
85
86 let mut radii = vec![0; separated.len()];
87 let mut left = 0;
88 let mut right = 0;
89 for center in 0..separated.len() {
90 let mut radius = 1;
91 if center < right {
92 let mirror = left + right - 1 - center;
93 radius = radii[mirror].min(right - center);
94 }
95 while center >= radius
96 && center + radius < separated.len()
97 && separated[center - radius] == separated[center + radius]
98 {
99 radius += 1;
100 }
101 radii[center] = radius;
102 if center + radius > right {
103 left = center + 1 - radius;
104 right = center + radius;
105 }
106 }
107 radii
108}
109
110/// 列の任意区間に対する操作を提供します。
111///
112/// `[T]` に実装されているため、`Vec<T>` や配列のスライスに対して利用できます。
113///
114/// 範囲引数は [`RangeBounds`] に従い、`..`, `l..`, `..r`, `l..r`, `l..=r` などを指定できます。
115/// 範囲は半開区間 `[start, end)` として扱われます。添字は0始まりで、変換後の範囲が
116/// `0 <= start <= end <= self.len()` を満たさない場合は panic します。
117pub trait SequenceExt<T> {
118 /// `range` で指定した区間が回文かどうかを返します。
119 ///
120 /// 範囲内の要素を先頭と末尾から順に比較します。空区間と1要素の区間は回文です。
121 /// 計算量は区間長を `L` として `O(L)`、追加メモリは `O(1)` です。
122 ///
123 /// # Examples
124 ///
125 /// ```
126 /// use atcoder::string::SequenceExt;
127 ///
128 /// let a = vec![1, 2, 3, 2, 1];
129 ///
130 /// assert!(a.is_palindrome(..));
131 /// assert!(a.is_palindrome(1..4));
132 /// assert!(a.is_palindrome(2..3));
133 /// assert!(!a.is_palindrome(0..4));
134 /// ```
135 fn is_palindrome<R: RangeBounds<usize>>(&self, range: R) -> bool
136 where
137 T: Eq;
138
139 /// `range` で指定した区間の要素順を反転します。
140 ///
141 /// 範囲外の要素は変更しません。空区間では何もしません。
142 /// 計算量は区間長を `L` として `O(L)`、追加メモリは `O(1)` です。
143 ///
144 /// # Examples
145 ///
146 /// ```
147 /// use atcoder::string::SequenceExt;
148 ///
149 /// let mut a = vec![1, 2, 3, 4, 5];
150 /// a.reverse_range(1..4);
151 ///
152 /// assert_eq!(a, vec![1, 4, 3, 2, 5]);
153 /// ```
154 fn reverse_range<R: RangeBounds<usize>>(&mut self, range: R);
155
156 /// `range` で指定した区間を左に `k` 個巡回シフトします。
157 ///
158 /// `k` が区間長以上の場合は、区間長で割った余りだけシフトします。たとえば `[1, 2, 3]` を `k = 1`
159 /// でシフトすると `[2, 3, 1]` になります。空区間に対して呼び出した場合は何もしません。
160 ///
161 /// 計算量は区間長を `L` として `O(L)`、追加メモリは `O(1)` です。
162 ///
163 /// # Examples
164 ///
165 /// ```
166 /// use atcoder::string::SequenceExt;
167 ///
168 /// let mut a = vec![1, 2, 3, 4, 5];
169 /// a.rotate_left_range(1..5, 2);
170 ///
171 /// assert_eq!(a, vec![1, 4, 5, 2, 3]);
172 /// ```
173 fn rotate_left_range<R: RangeBounds<usize>>(&mut self, range: R, k: usize);
174
175 /// `range` で指定した区間を右に `k` 個巡回シフトします。
176 ///
177 /// `k` が区間長以上の場合は、区間長で割った余りだけシフトします。たとえば `[1, 2, 3]` を `k = 1`
178 /// でシフトすると `[3, 1, 2]` になります。空区間に対して呼び出した場合は何もしません。
179 ///
180 /// 計算量は区間長を `L` として `O(L)`、追加メモリは `O(1)` です。
181 ///
182 /// # Examples
183 ///
184 /// ```
185 /// use atcoder::string::SequenceExt;
186 ///
187 /// let mut a = vec![1, 2, 3, 4, 5];
188 /// a.rotate_right_range(1..5, 2);
189 ///
190 /// assert_eq!(a, vec![1, 4, 5, 2, 3]);
191 /// ```
192 fn rotate_right_range<R: RangeBounds<usize>>(&mut self, range: R, k: usize);
193}
194
195impl<T> SequenceExt<T> for [T] {
196 fn is_palindrome<R: RangeBounds<usize>>(&self, range: R) -> bool
197 where
198 T: Eq,
199 {
200 let (l, r) = range_bounds(range, self.len());
201 let slice = &self[l..r];
202
203 slice.iter().eq(slice.iter().rev())
204 }
205
206 fn reverse_range<R: RangeBounds<usize>>(&mut self, range: R) {
207 let (l, r) = range_bounds(range, self.len());
208 self[l..r].reverse();
209 }
210
211 fn rotate_left_range<R: RangeBounds<usize>>(&mut self, range: R, k: usize) {
212 let (l, r) = range_bounds(range, self.len());
213 let len = r - l;
214
215 if len > 0 {
216 self[l..r].rotate_left(k % len);
217 }
218 }
219
220 fn rotate_right_range<R: RangeBounds<usize>>(&mut self, range: R, k: usize) {
221 let (l, r) = range_bounds(range, self.len());
222 let len = r - l;
223
224 if len > 0 {
225 self[l..r].rotate_right(k % len);
226 }
227 }
228}
229
230/// `RangeBounds<usize>` を半開区間 `[l, r)` に変換します。
231///
232/// `..`, `l..`, `..r`, `l..r`, `l..=r` などを受け付けます。
233/// 変換後の範囲が `0 <= l <= r <= len` を満たさない場合は panic します。
234fn range_bounds<R: RangeBounds<usize>>(range: R, len: usize) -> (usize, usize) {
235 let l = match range.start_bound() {
236 Bound::Included(&x) => x,
237 Bound::Excluded(&x) => x.checked_add(1).expect("range start bound overflow"),
238 Bound::Unbounded => 0,
239 };
240
241 let r = match range.end_bound() {
242 Bound::Included(&x) => x.checked_add(1).expect("range end bound overflow"),
243 Bound::Excluded(&x) => x,
244 Bound::Unbounded => len,
245 };
246
247 assert!(l <= r && r <= len, "range out of bounds");
248
249 (l, r)
250}
251
252/// 10進数の各桁を表す列を `usize` に変換します。
253///
254/// `[usize]` と `[char]` に実装されているため、`Vec<usize>` や `Vec<char>` にも
255/// そのまま利用できます。要素を左から順に10進数の桁として読み、先頭のゼロも通常の整数と同じ値にします。
256/// 空の列、10進数の桁として不正な要素、または `usize` の範囲を超える値に対しては `None` を返します。
257/// 計算量は要素数を `N` として `O(N)`、追加メモリは `O(1)` です。
258///
259/// # Examples
260///
261/// ```
262/// use atcoder::string::DecimalDigitsExt;
263///
264/// assert_eq!(vec![1, 2, 3].parse_usize(), Some(123));
265/// assert_eq!(vec!['4', '5', '6'].parse_usize(), Some(456));
266/// ```
267pub trait DecimalDigitsExt {
268 /// 各要素を10進数の一桁として解釈し、`usize` へ変換します。
269 ///
270 /// `[usize]` の要素はそれぞれ `0..=9` である必要があります。`[char]` の要素は
271 /// [`char::to_digit`] で基数10の数字として認識される必要があります。
272 fn parse_usize(&self) -> Option<usize>;
273}
274
275impl DecimalDigitsExt for [usize] {
276 fn parse_usize(&self) -> Option<usize> {
277 if self.is_empty() {
278 return None;
279 }
280
281 self.iter().try_fold(0_usize, |value, &digit| {
282 if digit >= 10 {
283 return None;
284 }
285 value.checked_mul(10)?.checked_add(digit)
286 })
287 }
288}
289
290impl DecimalDigitsExt for [char] {
291 fn parse_usize(&self) -> Option<usize> {
292 if self.is_empty() {
293 return None;
294 }
295
296 self.iter().try_fold(0_usize, |value, &digit| {
297 let digit = digit.to_digit(10)? as usize;
298 value.checked_mul(10)?.checked_add(digit)
299 })
300 }
301}
302
303#[cfg(test)]
304mod tests {
305 use super::{manacher, AlphaExt, AlphaIndexExt, DecimalDigitsExt};
306
307 #[test]
308 fn finds_even_palindrome() {
309 assert_eq!(manacher(b"abba")[4] - 1, 4);
310 assert_eq!(b'Z'.to_idx(), 25);
311 }
312
313 #[test]
314 fn converts_alphabet_indices_to_lowercase_letters() {
315 assert_eq!(0_usize.to_alpha(), 'a');
316 assert_eq!(25_usize.to_alpha(), 'z');
317 assert_eq!(0_u8.to_alpha(), 'a');
318 assert_eq!(25_u8.to_alpha(), 'z');
319 }
320
321 #[test]
322 #[should_panic(expected = "alphabet index out of range")]
323 fn rejects_invalid_alphabet_index() {
324 26_usize.to_alpha();
325 }
326
327 #[test]
328 fn parses_decimal_digits() {
329 assert_eq!([0, 1, 2, 3].parse_usize(), Some(123));
330 assert_eq!(['0', '4', '5', '6'].parse_usize(), Some(456));
331 }
332
333 #[test]
334 fn rejects_invalid_or_overflowing_decimal_digits() {
335 assert_eq!(Vec::<usize>::new().parse_usize(), None);
336 assert_eq!([1, 10].parse_usize(), None);
337 assert_eq!(['1', 'x'].parse_usize(), None);
338 assert_eq!(vec![9; usize::BITS as usize].parse_usize(), None);
339 }
340}