longest_increasing_subsequence/lib.rs
1/*!
2
3[](https://docs.rs/longest-increasing-subsequence/)
4[](https://crates.io/crates/longest-increasing-subsequence)
5[](https://crates.io/crates/longest-increasing-subsequence)
6[](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}