forked from TheAlgorithms/Rust
-
Notifications
You must be signed in to change notification settings - Fork 1
/
longest_increasing_subsequence.rs
109 lines (96 loc) · 3.35 KB
/
longest_increasing_subsequence.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/// Finds the longest increasing subsequence and returns it.
///
/// If multiple subsequences with the longest possible subsequence length can be found, the
/// subsequence which appeared first will be returned (see `test_example_1`).
///
/// Inspired by [this LeetCode problem](https://leetcode.com/problems/longest-increasing-subsequence/).
pub fn longest_increasing_subsequence<T: Ord + Clone>(input_array: &[T]) -> Vec<T> {
let n = input_array.len();
if n <= 1 {
return input_array.to_vec();
}
let mut increasing_sequence: Vec<(T, usize)> = Vec::new();
let mut previous = vec![0_usize; n];
increasing_sequence.push((input_array[0].clone(), 1));
for i in 1..n {
let value = input_array[i].clone();
if value > increasing_sequence.last().unwrap().0 {
previous[i] = increasing_sequence.last().unwrap().1 - 1;
increasing_sequence.push((value, i + 1));
continue;
}
let change_position = increasing_sequence
.binary_search(&(value.clone(), 0))
.unwrap_or_else(|x| x);
increasing_sequence[change_position] = (value, i + 1);
previous[i] = match change_position {
0 => i,
other => increasing_sequence[other - 1].1 - 1,
};
}
// Construct subsequence
let mut out: Vec<T> = Vec::with_capacity(increasing_sequence.len());
out.push(increasing_sequence.last().unwrap().0.clone());
let mut current_index = increasing_sequence.last().unwrap().1 - 1;
while previous[current_index] != current_index {
current_index = previous[current_index];
out.push(input_array[current_index].clone());
}
out.into_iter().rev().collect()
}
#[cfg(test)]
mod tests {
use super::longest_increasing_subsequence;
#[test]
/// Need to specify generic type T in order to function
fn test_empty_vec() {
assert_eq!(longest_increasing_subsequence::<i32>(&vec![]), vec![]);
}
#[test]
fn test_example_1() {
assert_eq!(
longest_increasing_subsequence(&vec![10, 9, 2, 5, 3, 7, 101, 18]),
vec![2, 3, 7, 18]
);
}
#[test]
fn test_example_2() {
assert_eq!(
longest_increasing_subsequence(&vec![0, 1, 0, 3, 2, 3]),
vec![0, 1, 2, 3]
);
}
#[test]
fn test_example_3() {
assert_eq!(
longest_increasing_subsequence(&vec![7, 7, 7, 7, 7, 7, 7]),
vec![7]
);
}
#[test]
fn test_tle() {
let mut input_array = vec![0i64; 1e5 as usize];
let mut expected_result: Vec<i64> = Vec::with_capacity(5e4 as usize);
for (idx, num) in input_array.iter_mut().enumerate() {
match idx % 2 {
0 => {
*num = idx as i64;
expected_result.push(*num);
}
1 => *num = -(idx as i64),
_ => unreachable!(),
}
}
expected_result[0] = -1;
assert_eq!(
longest_increasing_subsequence(&input_array),
expected_result
);
// should be [-1, 2, 4, 6, 8, ...]
// the first number is not 0, it would be replaced by -1 before 2 is added
}
#[test]
fn test_negative_elements() {
assert_eq!(longest_increasing_subsequence(&vec![-2, -1]), vec![-2, -1]);
}
}