sliding_window/
lib.rs

1use std::collections::VecDeque;
2
3/// 幅 `window_width` の区間すべてに対し最小値を求めます。
4///
5/// 配列 `a` に対し次で定める配列 `b` を求めます。
6///
7/// - `a` の長さ `a.len()` を `n` とする
8/// - `b[0]`: `min(a[0], a[1], ..., a[window_width - 1])`
9/// - `b[1]`: `min(a[1], a[2], ..., a[window_width])`
10/// - ...
11/// - `b[n - window_width]`: `min(a[n - window_width], ..., a[n - 2], a[n - 1])`
12///
13/// [実装の参考資料](https://qiita.com/kuuso1/items/318d42cd089a49eeb332)
14///
15/// # Panics
16///
17/// if `window_width` is zero or is greater than `a.len()`.
18///
19/// # Examples
20///
21/// ```
22/// use sliding_window::sliding_window_minimum;
23///
24/// let a = vec![4, 7, 7, 8, 5, 7, 6, 9, 9, 2, 8, 3];
25/// let minimums = sliding_window_minimum(&a, 6);
26/// assert_eq!(
27///     minimums,
28///     vec![
29///         &4, // 4 7 7 8 5 7
30///         &5, //   7 7 8 5 7 6
31///         &5, //     7 8 5 7 6 9
32///         &5, //       8 5 7 6 9 9
33///         &2, //         5 7 6 9 9 2
34///         &2, //           7 6 9 9 2 8
35///         &2, //             6 9 9 2 8 3
36///     ]
37/// );
38/// ```
39pub fn sliding_window_minimum<T>(a: &[T], window_width: usize) -> Vec<&T>
40where
41    T: Ord,
42{
43    sliding_window(a, window_width, |last, new| last >= new)
44}
45
46/// [`sliding_window_minimum`](fn.sliding_window_minimum.html) の最大値バージョンです。
47pub fn sliding_window_maximum<T>(a: &[T], window_width: usize) -> Vec<&T>
48where
49    T: Ord,
50{
51    sliding_window(a, window_width, |last, new| last <= new)
52}
53
54fn sliding_window<T, F>(a: &[T], window_width: usize, pop_back_cond: F) -> Vec<&T>
55where
56    T: Ord,
57    F: Fn(&T, &T) -> bool, // (last, new)
58{
59    assert!(0 < window_width && window_width <= a.len());
60    let mut result = Vec::new();
61    let mut positions: VecDeque<usize> = VecDeque::new();
62    for (i, v) in a.iter().enumerate() {
63        while let Some(last) = positions.back().copied() {
64            if pop_back_cond(&a[last], v) {
65                positions.pop_back();
66            } else {
67                break;
68            }
69        }
70        positions.push_back(i);
71        if i >= window_width - 1 {
72            let p = positions.front().copied().unwrap();
73            result.push(&a[p]);
74            if p == i - (window_width - 1) {
75                positions.pop_front();
76            }
77        }
78    }
79    result
80}
81
82#[cfg(test)]
83mod tests {
84    use crate::{sliding_window_maximum, sliding_window_minimum};
85
86    #[test]
87    fn test_min() {
88        let a = vec![2, 2, 3, 6, 0, 6, 7, 9, 7, 7, 4, 9];
89        assert_eq!(
90            sliding_window_minimum(&a, 4),
91            vec![
92                &2, // 2 2 3 6
93                &0, //   2 3 6 0
94                &0, //     3 6 0 6
95                &0, //       6 0 6 7
96                &0, //         0 6 7 9
97                &6, //           6 7 9 7
98                &7, //             7 9 7 7
99                &4, //               9 7 7 4
100                &4, //                 7 7 4 9
101            ]
102        );
103
104        assert_eq!(sliding_window_minimum(&a, 1), a.iter().collect::<Vec<_>>());
105
106        assert_eq!(
107            sliding_window_minimum(&a, a.len()),
108            vec![a.iter().min().unwrap()],
109        );
110    }
111
112    #[test]
113    fn test_max() {
114        let a = vec![2, 2, 3, 6, 0, 6, 7, 9, 7, 7, 4, 9];
115        assert_eq!(
116            sliding_window_maximum(&a, 4),
117            vec![
118                &6, // 2 2 3 6
119                &6, //   2 3 6 0
120                &6, //     3 6 0 6
121                &7, //       6 0 6 7
122                &9, //         0 6 7 9
123                &9, //           6 7 9 7
124                &9, //             7 9 7 7
125                &9, //               9 7 7 4
126                &9, //                 7 7 4 9
127            ]
128        );
129
130        assert_eq!(sliding_window_maximum(&a, 1), a.iter().collect::<Vec<_>>());
131
132        assert_eq!(
133            sliding_window_maximum(&a, a.len()),
134            vec![a.iter().max().unwrap()],
135        );
136    }
137
138    #[test]
139    #[should_panic]
140    fn test_empty_0() {
141        assert!(sliding_window_minimum::<u32>(&[], 0).is_empty());
142    }
143
144    #[test]
145    #[should_panic]
146    fn test_empty_1() {
147        assert!(sliding_window_minimum::<u32>(&[], 1).is_empty());
148    }
149}