Skip to main content

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}