longest_increasing_subsequence/
lib.rs

1/*!
2
3[![](https://docs.rs/longest-increasing-subsequence/badge.svg)](https://docs.rs/longest-increasing-subsequence/)
4[![](https://img.shields.io/crates/v/longest-increasing-subsequence.svg)](https://crates.io/crates/longest-increasing-subsequence)
5[![](https://img.shields.io/crates/d/longest-increasing-subsequence.svg)](https://crates.io/crates/longest-increasing-subsequence)
6[![Build Status](https://dev.azure.com/fitzgen/longest-increasing-subsequence/_apis/build/status/fitzgen.longest-increasing-subsequence?branchName=master)](https://dev.azure.com/fitzgen/longest-increasing-subsequence/_build/latest?definitionId=1&branchName=master)
7
8## Longest Increasing Subsequence
9
10> The longest increasing subsequence problem is to find a subsequence of a given
11> sequence in which the subsequence's elements are in sorted order, lowest to
12> highest, and in which the subsequence is as long as possible. This subsequence
13> is not necessarily contiguous, or unique.
14
15— [Wikipedia](https://en.wikipedia.org/wiki/Longest_increasing_subsequence)
16
17For example, consider this sequence of integers:
18
19> 2, 9, 4, 7, 3, 4, 5
20
21The longest increasing subsequence (LIS) for this sequence is *2, 3, 4, 5*.
22
23Note that there is not always a *singular* LIS. Consider this sequence:
24
25> 2, 6, 5
26
27In this sequence, both *2, 5* and *2, 6* are LISs.
28
29## API
30
31This crate exposes two functions for finding a longest increasing subsequence
32within a slice:
33
341. The high-level, easy-to-use `lis` function takes any slice of `T: Ord` and
35returns the LIS as a vector of indices into that slice.
36
372. The low-level `lis_with` function takes a custom comparator and lets you
38bring your own allocations (which lets you choose to reuse allocations or use a
39custom allocator).
40
41Both functions use the same underlying algorithm. They execute in *O(n log n)*
42time and use *O(n)* memory.
43
44## Example
45
46```
47use longest_increasing_subsequence::lis;
48
49let xs = vec![9, 2, 8, 3, 5];
50for i in lis(&xs) {
51    println!("{} at index {}", xs[i], i);
52}
53
54// Prints:
55// 2 at index 1
56// 3 at index 3
57// 5 at index 4
58```
59
60 */
61
62/// The high-level, easy-to-use function for finding a longest increasing
63/// subsequence.
64///
65/// Takes any slice `&[T]` and uses the `T: Ord` implementation to determine the
66/// LIS.
67///
68/// The LIS is returned as a vector of indices into the input items slice.
69///
70/// # Example
71///
72/// ```
73/// use longest_increasing_subsequence::lis;
74///
75/// let xs = vec![9, 2, 8, 3, 5];
76/// for i in lis(&xs) {
77///     println!("{} at index {}", xs[i], i);
78/// }
79///
80/// // Prints:
81/// // 2 at index 1
82/// // 3 at index 3
83/// // 5 at index 4
84/// ```
85pub fn lis<T>(items: &[T]) -> Vec<usize>
86where
87    T: Ord,
88{
89    let mut seq = Vec::new();
90    let p = &mut vec![0; items.len()];
91    let m = &mut vec![0; items.len()];
92    lis_with(items, &mut seq, |a, b| a < b, p, m);
93    seq.reverse();
94    seq
95}
96
97/// The low-level function for finding a longest increasing subsequence.
98///
99/// This low-level function allows you to:
100///
101/// * customize the comparator function to something other than `T: Ord`,
102///
103/// * bring your own allocations for the algorithm's temporary scratch space (so
104/// you can reuse the same allocations across multiple `lis_with` calls, or use
105/// a custom allocator, etc...),
106///
107/// * and collect the resulting LIS into a custom collection data structure.
108///
109/// Note that the `out_seq` is given the indices of the LIS in **reverse order**
110/// from the end of the LIS first to the start of the LIS last.
111///
112/// ## Panics
113///
114/// Panics if `items`, `predecessors`, and `starts` do not all have the same
115/// length.
116///
117/// ## Example
118///
119/// ```
120/// use longest_increasing_subsequence::lis_with;
121/// use std::collections::HashSet;
122///
123/// // Create allocations for the algorithm's scratch space.
124/// let mut predecessors = Vec::new();
125/// let mut starts = Vec::new();
126///
127/// // And a collection to contain the results.
128/// let mut results = HashSet::new();
129///
130/// // A slice whose LIS we would like to find.
131/// let xs = vec![9, 2, 8, 3, 5];
132///
133/// // Ensure our allocations have enough space.
134/// predecessors.resize_with(xs.len(), Default::default);
135/// starts.resize_with(xs.len(), Default::default);
136///
137/// lis_with(
138///     &xs,
139///     &mut results,
140///     |a, b| a < b,
141///     &mut predecessors,
142///     &mut starts,
143/// );
144///
145/// assert_eq!(results, vec![1, 3, 4].into_iter().collect());
146///
147/// // Another slice whose LIS we would like to find.
148/// let ys = vec![9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
149///
150/// // We are going to reuse our previous scratch space. Again, ensure we
151/// // have enough space.
152/// predecessors.resize_with(ys.len(), Default::default);
153/// starts.resize_with(ys.len(), Default::default);
154///
155/// results.clear();
156/// lis_with(
157///     &ys,
158///     &mut results,
159///     |a, b| a < b,
160///     &mut predecessors,
161///     &mut starts,
162/// );
163///
164/// assert_eq!(results, vec![9, 10, 11, 12, 13, 14, 15, 16, 17, 18].into_iter().collect());
165/// ```
166pub fn lis_with<T, S, F>(
167    items: &[T],
168    out_seq: &mut S,
169    mut less_than: F,
170    predecessors: &mut [usize],
171    starts: &mut [usize],
172) where
173    S: Extend<usize>,
174    F: FnMut(&T, &T) -> bool,
175{
176    assert_eq!(items.len(), predecessors.len());
177    assert_eq!(predecessors.len(), starts.len());
178
179    if items.is_empty() {
180        return;
181    }
182
183    unsafe {
184        let mut k = 0;
185        let len = items.len();
186
187        for i in 0..len {
188            let j = *get_unchecked(starts, k);
189
190            if less_than(get_unchecked(items, j), get_unchecked(items, i)) {
191                set_unchecked(predecessors, i, j);
192                k += 1;
193                set_unchecked(starts, k, i);
194                continue;
195            }
196
197            let mut lo = 0;
198            let mut hi = k;
199
200            while lo < hi {
201                // Get the mid point while handling overflow.
202                let mid = (lo >> 1) + (hi >> 1) + (lo & hi & 1);
203                if less_than(
204                    get_unchecked(items, *get_unchecked(starts, mid)),
205                    get_unchecked(items, i),
206                ) {
207                    lo = mid + 1;
208                } else {
209                    hi = mid;
210                }
211            }
212
213            if less_than(
214                get_unchecked(items, i),
215                get_unchecked(items, *get_unchecked(starts, lo)),
216            ) {
217                if lo > 0 {
218                    set_unchecked(predecessors, i, *get_unchecked(starts, lo - 1));
219                }
220                set_unchecked(starts, lo, i);
221            }
222        }
223
224        let u = k + 1;
225        let mut v = *get_unchecked(starts, k);
226        out_seq.extend((0..u).rev().map(|_| {
227            let w = v;
228            v = *get_unchecked(predecessors, v);
229            w
230        }));
231    }
232}
233
234#[inline(always)]
235unsafe fn get_unchecked<T>(slice: &[T], index: usize) -> &T {
236    debug_assert!(index < slice.len());
237    slice.get_unchecked(index)
238}
239
240#[inline(always)]
241unsafe fn set_unchecked<T>(slice: &mut [T], index: usize, value: T) {
242    debug_assert!(index < slice.len());
243    *slice.get_unchecked_mut(index) = value;
244}