-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor Longest Continuous Increasing Subsequence Implementation (#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
- Loading branch information
Showing
1 changed file
with
76 additions
and
57 deletions.
There are no files selected for viewing
133 changes: 76 additions & 57 deletions
133
src/dynamic_programming/longest_continuous_increasing_subsequence.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,74 +1,93 @@ | ||
pub fn longest_continuous_increasing_subsequence<T: Ord>(input_array: &[T]) -> &[T] { | ||
let length: usize = input_array.len(); | ||
use std::cmp::Ordering; | ||
|
||
//Handle the base cases | ||
if length <= 1 { | ||
return input_array; | ||
/// Finds the longest continuous increasing subsequence in a slice. | ||
/// | ||
/// Given a slice of elements, this function returns a slice representing | ||
/// the longest continuous subsequence where each element is strictly | ||
/// less than the following element. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `arr` - A reference to a slice of elements | ||
/// | ||
/// # Returns | ||
/// | ||
/// A subslice of the input, representing the longest continuous increasing subsequence. | ||
/// If there are multiple subsequences of the same length, the function returns the first one found. | ||
pub fn longest_continuous_increasing_subsequence<T: Ord>(arr: &[T]) -> &[T] { | ||
if arr.len() <= 1 { | ||
return arr; | ||
} | ||
|
||
//Create the array to store the longest subsequence at each location | ||
let mut tracking_vec = vec![1; length]; | ||
let mut start = 0; | ||
let mut max_start = 0; | ||
let mut max_len = 1; | ||
let mut curr_len = 1; | ||
|
||
//Iterate through the input and store longest subsequences at each location in the vector | ||
for i in (0..length - 1).rev() { | ||
if input_array[i] < input_array[i + 1] { | ||
tracking_vec[i] = tracking_vec[i + 1] + 1; | ||
for i in 1..arr.len() { | ||
match arr[i - 1].cmp(&arr[i]) { | ||
// include current element is greater than or equal to the previous | ||
// one elements in the current increasing sequence | ||
Ordering::Less | Ordering::Equal => { | ||
curr_len += 1; | ||
} | ||
// reset when a strictly decreasing element is found | ||
Ordering::Greater => { | ||
if curr_len > max_len { | ||
max_len = curr_len; | ||
max_start = start; | ||
} | ||
// reset start to the current position | ||
start = i; | ||
// reset current length | ||
curr_len = 1; | ||
} | ||
} | ||
} | ||
|
||
//Find the longest subsequence | ||
let mut max_index: usize = 0; | ||
let mut max_value: i32 = 0; | ||
for (index, value) in tracking_vec.iter().enumerate() { | ||
if value > &max_value { | ||
max_value = *value; | ||
max_index = index; | ||
} | ||
// final check for the last sequence | ||
if curr_len > max_len { | ||
max_len = curr_len; | ||
max_start = start; | ||
} | ||
|
||
&input_array[max_index..max_index + max_value as usize] | ||
&arr[max_start..max_start + max_len] | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::longest_continuous_increasing_subsequence; | ||
|
||
#[test] | ||
fn test_longest_increasing_subsequence() { | ||
//Base Cases | ||
let base_case_array: [i32; 0] = []; | ||
assert_eq!( | ||
&longest_continuous_increasing_subsequence(&base_case_array), | ||
&[] | ||
); | ||
assert_eq!(&longest_continuous_increasing_subsequence(&[1]), &[1]); | ||
use super::*; | ||
|
||
//Normal i32 Cases | ||
assert_eq!( | ||
&longest_continuous_increasing_subsequence(&[1, 2, 3, 4]), | ||
&[1, 2, 3, 4] | ||
); | ||
assert_eq!( | ||
&longest_continuous_increasing_subsequence(&[1, 2, 2, 3, 4, 2]), | ||
&[2, 3, 4] | ||
); | ||
assert_eq!( | ||
&longest_continuous_increasing_subsequence(&[5, 4, 3, 2, 1]), | ||
&[5] | ||
); | ||
assert_eq!( | ||
&longest_continuous_increasing_subsequence(&[5, 4, 3, 4, 2, 1]), | ||
&[3, 4] | ||
); | ||
macro_rules! test_cases { | ||
($($name:ident: $test_case:expr,)*) => { | ||
$( | ||
#[test] | ||
fn $name() { | ||
let (input, expected) = $test_case; | ||
assert_eq!(longest_continuous_increasing_subsequence(input), expected); | ||
} | ||
)* | ||
}; | ||
} | ||
|
||
//Non-Numeric case | ||
assert_eq!( | ||
&longest_continuous_increasing_subsequence(&['a', 'b', 'c']), | ||
&['a', 'b', 'c'] | ||
); | ||
assert_eq!( | ||
&longest_continuous_increasing_subsequence(&['d', 'c', 'd']), | ||
&['c', 'd'] | ||
); | ||
test_cases! { | ||
empty_array: (&[] as &[isize], &[] as &[isize]), | ||
single_element: (&[1], &[1]), | ||
all_increasing: (&[1, 2, 3, 4, 5], &[1, 2, 3, 4, 5]), | ||
all_decreasing: (&[5, 4, 3, 2, 1], &[5]), | ||
with_equal_elements: (&[1, 2, 2, 3, 4, 2], &[1, 2, 2, 3, 4]), | ||
increasing_with_plateau: (&[1, 2, 2, 2, 3, 3, 4], &[1, 2, 2, 2, 3, 3, 4]), | ||
mixed_elements: (&[5, 4, 3, 4, 2, 1], &[3, 4]), | ||
alternating_increase_decrease: (&[1, 2, 1, 2, 1, 2], &[1, 2]), | ||
zigzag: (&[1, 3, 2, 4, 3, 5], &[1, 3]), | ||
single_negative_element: (&[-1], &[-1]), | ||
negative_and_positive_mixed: (&[-2, -1, 0, 1, 2, 3], &[-2, -1, 0, 1, 2, 3]), | ||
increasing_then_decreasing: (&[1, 2, 3, 4, 3, 2, 1], &[1, 2, 3, 4]), | ||
single_increasing_subsequence_later: (&[3, 2, 1, 1, 2, 3, 4], &[1, 1, 2, 3, 4]), | ||
longer_subsequence_at_start: (&[5, 6, 7, 8, 9, 2, 3, 4, 5], &[5, 6, 7, 8, 9]), | ||
longer_subsequence_at_end: (&[2, 3, 4, 10, 5, 6, 7, 8, 9], &[5, 6, 7, 8, 9]), | ||
longest_subsequence_at_start: (&[2, 3, 4, 5, 1, 0], &[2, 3, 4, 5]), | ||
longest_subsequence_at_end: (&[1, 7, 2, 3, 4, 5,], &[2, 3, 4, 5]), | ||
repeated_elements: (&[1, 1, 1, 1, 1], &[1, 1, 1, 1, 1]), | ||
} | ||
} |