Skip to content

Commit bc8d6fa

Browse files
authored
Refactor Longest Continuous Increasing Subsequence Implementation (TheAlgorithms#800)
ref: refactor implementation - remove `tracking_vec` to reduce mem usage and simplify logic - keep track of the `start` of the curr subseq and updated `max_start` and `max_len` when a longer subseq was found - rewrite tests with macro
1 parent 12f2764 commit bc8d6fa

File tree

1 file changed

+76
-57
lines changed

1 file changed

+76
-57
lines changed
Lines changed: 76 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,93 @@
1-
pub fn longest_continuous_increasing_subsequence<T: Ord>(input_array: &[T]) -> &[T] {
2-
let length: usize = input_array.len();
1+
use std::cmp::Ordering;
32

4-
//Handle the base cases
5-
if length <= 1 {
6-
return input_array;
3+
/// Finds the longest continuous increasing subsequence in a slice.
4+
///
5+
/// Given a slice of elements, this function returns a slice representing
6+
/// the longest continuous subsequence where each element is strictly
7+
/// less than the following element.
8+
///
9+
/// # Arguments
10+
///
11+
/// * `arr` - A reference to a slice of elements
12+
///
13+
/// # Returns
14+
///
15+
/// A subslice of the input, representing the longest continuous increasing subsequence.
16+
/// If there are multiple subsequences of the same length, the function returns the first one found.
17+
pub fn longest_continuous_increasing_subsequence<T: Ord>(arr: &[T]) -> &[T] {
18+
if arr.len() <= 1 {
19+
return arr;
720
}
821

9-
//Create the array to store the longest subsequence at each location
10-
let mut tracking_vec = vec![1; length];
22+
let mut start = 0;
23+
let mut max_start = 0;
24+
let mut max_len = 1;
25+
let mut curr_len = 1;
1126

12-
//Iterate through the input and store longest subsequences at each location in the vector
13-
for i in (0..length - 1).rev() {
14-
if input_array[i] < input_array[i + 1] {
15-
tracking_vec[i] = tracking_vec[i + 1] + 1;
27+
for i in 1..arr.len() {
28+
match arr[i - 1].cmp(&arr[i]) {
29+
// include current element is greater than or equal to the previous
30+
// one elements in the current increasing sequence
31+
Ordering::Less | Ordering::Equal => {
32+
curr_len += 1;
33+
}
34+
// reset when a strictly decreasing element is found
35+
Ordering::Greater => {
36+
if curr_len > max_len {
37+
max_len = curr_len;
38+
max_start = start;
39+
}
40+
// reset start to the current position
41+
start = i;
42+
// reset current length
43+
curr_len = 1;
44+
}
1645
}
1746
}
1847

19-
//Find the longest subsequence
20-
let mut max_index: usize = 0;
21-
let mut max_value: i32 = 0;
22-
for (index, value) in tracking_vec.iter().enumerate() {
23-
if value > &max_value {
24-
max_value = *value;
25-
max_index = index;
26-
}
48+
// final check for the last sequence
49+
if curr_len > max_len {
50+
max_len = curr_len;
51+
max_start = start;
2752
}
2853

29-
&input_array[max_index..max_index + max_value as usize]
54+
&arr[max_start..max_start + max_len]
3055
}
3156

3257
#[cfg(test)]
3358
mod tests {
34-
use super::longest_continuous_increasing_subsequence;
35-
36-
#[test]
37-
fn test_longest_increasing_subsequence() {
38-
//Base Cases
39-
let base_case_array: [i32; 0] = [];
40-
assert_eq!(
41-
&longest_continuous_increasing_subsequence(&base_case_array),
42-
&[]
43-
);
44-
assert_eq!(&longest_continuous_increasing_subsequence(&[1]), &[1]);
59+
use super::*;
4560

46-
//Normal i32 Cases
47-
assert_eq!(
48-
&longest_continuous_increasing_subsequence(&[1, 2, 3, 4]),
49-
&[1, 2, 3, 4]
50-
);
51-
assert_eq!(
52-
&longest_continuous_increasing_subsequence(&[1, 2, 2, 3, 4, 2]),
53-
&[2, 3, 4]
54-
);
55-
assert_eq!(
56-
&longest_continuous_increasing_subsequence(&[5, 4, 3, 2, 1]),
57-
&[5]
58-
);
59-
assert_eq!(
60-
&longest_continuous_increasing_subsequence(&[5, 4, 3, 4, 2, 1]),
61-
&[3, 4]
62-
);
61+
macro_rules! test_cases {
62+
($($name:ident: $test_case:expr,)*) => {
63+
$(
64+
#[test]
65+
fn $name() {
66+
let (input, expected) = $test_case;
67+
assert_eq!(longest_continuous_increasing_subsequence(input), expected);
68+
}
69+
)*
70+
};
71+
}
6372

64-
//Non-Numeric case
65-
assert_eq!(
66-
&longest_continuous_increasing_subsequence(&['a', 'b', 'c']),
67-
&['a', 'b', 'c']
68-
);
69-
assert_eq!(
70-
&longest_continuous_increasing_subsequence(&['d', 'c', 'd']),
71-
&['c', 'd']
72-
);
73+
test_cases! {
74+
empty_array: (&[] as &[isize], &[] as &[isize]),
75+
single_element: (&[1], &[1]),
76+
all_increasing: (&[1, 2, 3, 4, 5], &[1, 2, 3, 4, 5]),
77+
all_decreasing: (&[5, 4, 3, 2, 1], &[5]),
78+
with_equal_elements: (&[1, 2, 2, 3, 4, 2], &[1, 2, 2, 3, 4]),
79+
increasing_with_plateau: (&[1, 2, 2, 2, 3, 3, 4], &[1, 2, 2, 2, 3, 3, 4]),
80+
mixed_elements: (&[5, 4, 3, 4, 2, 1], &[3, 4]),
81+
alternating_increase_decrease: (&[1, 2, 1, 2, 1, 2], &[1, 2]),
82+
zigzag: (&[1, 3, 2, 4, 3, 5], &[1, 3]),
83+
single_negative_element: (&[-1], &[-1]),
84+
negative_and_positive_mixed: (&[-2, -1, 0, 1, 2, 3], &[-2, -1, 0, 1, 2, 3]),
85+
increasing_then_decreasing: (&[1, 2, 3, 4, 3, 2, 1], &[1, 2, 3, 4]),
86+
single_increasing_subsequence_later: (&[3, 2, 1, 1, 2, 3, 4], &[1, 1, 2, 3, 4]),
87+
longer_subsequence_at_start: (&[5, 6, 7, 8, 9, 2, 3, 4, 5], &[5, 6, 7, 8, 9]),
88+
longer_subsequence_at_end: (&[2, 3, 4, 10, 5, 6, 7, 8, 9], &[5, 6, 7, 8, 9]),
89+
longest_subsequence_at_start: (&[2, 3, 4, 5, 1, 0], &[2, 3, 4, 5]),
90+
longest_subsequence_at_end: (&[1, 7, 2, 3, 4, 5,], &[2, 3, 4, 5]),
91+
repeated_elements: (&[1, 1, 1, 1, 1], &[1, 1, 1, 1, 1]),
7392
}
7493
}

0 commit comments

Comments
 (0)