Skip to content

Commit 5f33ef8

Browse files
committed
Merge branch 'master' of https://github.com/TheAlgorithms/Rust into email-address
2 parents 7bfa0d8 + 72dc88f commit 5f33ef8

File tree

2 files changed

+103
-71
lines changed

2 files changed

+103
-71
lines changed
Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,82 @@
1-
/// ## maximum subarray via Dynamic Programming
1+
//! This module provides a function to find the the largest sum of the subarray
2+
//! in a given array of integers using dynamic programming. It also includes
3+
//! tests to verify the correctness of the implementation.
24
3-
/// maximum_subarray(array) find the subarray (containing at least one number) which has the largest sum
4-
/// and return its sum.
5+
/// Custom error type for maximum subarray
6+
#[derive(Debug, PartialEq)]
7+
pub enum MaximumSubarrayError {
8+
EmptyArray,
9+
}
10+
11+
/// Finds the subarray (containing at least one number) which has the largest sum
12+
/// and returns its sum.
513
///
614
/// A subarray is a contiguous part of an array.
715
///
8-
/// Arguments:
9-
/// * `array` - an integer array
10-
/// Complexity
11-
/// - time complexity: O(array.length),
12-
/// - space complexity: O(array.length),
13-
pub fn maximum_subarray(array: &[i32]) -> i32 {
14-
let mut dp = vec![0; array.len()];
15-
dp[0] = array[0];
16-
let mut result = dp[0];
17-
18-
for i in 1..array.len() {
19-
if dp[i - 1] > 0 {
20-
dp[i] = dp[i - 1] + array[i];
21-
} else {
22-
dp[i] = array[i];
23-
}
24-
result = result.max(dp[i]);
16+
/// # Arguments
17+
///
18+
/// * `array` - A slice of integers.
19+
///
20+
/// # Returns
21+
///
22+
/// A `Result` which is:
23+
/// * `Ok(isize)` representing the largest sum of a contiguous subarray.
24+
/// * `Err(MaximumSubarrayError)` if the array is empty.
25+
///
26+
/// # Complexity
27+
///
28+
/// * Time complexity: `O(array.len())`
29+
/// * Space complexity: `O(1)`
30+
pub fn maximum_subarray(array: &[isize]) -> Result<isize, MaximumSubarrayError> {
31+
if array.is_empty() {
32+
return Err(MaximumSubarrayError::EmptyArray);
2533
}
2634

27-
result
35+
let mut cur_sum = array[0];
36+
let mut max_sum = cur_sum;
37+
38+
for &x in &array[1..] {
39+
cur_sum = (cur_sum + x).max(x);
40+
max_sum = max_sum.max(cur_sum);
41+
}
42+
43+
Ok(max_sum)
2844
}
2945

3046
#[cfg(test)]
3147
mod tests {
3248
use super::*;
3349

34-
#[test]
35-
fn non_negative() {
36-
//the maximum value: 1 + 0 + 5 + 8 = 14
37-
let array = vec![1, 0, 5, 8];
38-
assert_eq!(maximum_subarray(&array), 14);
39-
}
40-
41-
#[test]
42-
fn negative() {
43-
//the maximum value: -1
44-
let array = vec![-3, -1, -8, -2];
45-
assert_eq!(maximum_subarray(&array), -1);
46-
}
47-
48-
#[test]
49-
fn normal() {
50-
//the maximum value: 3 + (-2) + 5 = 6
51-
let array = vec![-4, 3, -2, 5, -8];
52-
assert_eq!(maximum_subarray(&array), 6);
50+
macro_rules! maximum_subarray_tests {
51+
($($name:ident: $tc:expr,)*) => {
52+
$(
53+
#[test]
54+
fn $name() {
55+
let (array, expected) = $tc;
56+
assert_eq!(maximum_subarray(&array), expected);
57+
}
58+
)*
59+
}
5360
}
5461

55-
#[test]
56-
fn single_element() {
57-
let array = vec![6];
58-
assert_eq!(maximum_subarray(&array), 6);
59-
let array = vec![-6];
60-
assert_eq!(maximum_subarray(&array), -6);
62+
maximum_subarray_tests! {
63+
test_all_non_negative: (vec![1, 0, 5, 8], Ok(14)),
64+
test_all_negative: (vec![-3, -1, -8, -2], Ok(-1)),
65+
test_mixed_negative_and_positive: (vec![-4, 3, -2, 5, -8], Ok(6)),
66+
test_single_element_positive: (vec![6], Ok(6)),
67+
test_single_element_negative: (vec![-6], Ok(-6)),
68+
test_mixed_elements: (vec![-2, 1, -3, 4, -1, 2, 1, -5, 4], Ok(6)),
69+
test_empty_array: (vec![], Err(MaximumSubarrayError::EmptyArray)),
70+
test_all_zeroes: (vec![0, 0, 0, 0], Ok(0)),
71+
test_single_zero: (vec![0], Ok(0)),
72+
test_alternating_signs: (vec![3, -2, 5, -1], Ok(6)),
73+
test_all_negatives_with_one_positive: (vec![-3, -4, 1, -7, -2], Ok(1)),
74+
test_all_positives_with_one_negative: (vec![3, 4, -1, 7, 2], Ok(15)),
75+
test_all_positives: (vec![2, 3, 1, 5], Ok(11)),
76+
test_large_values: (vec![1000, -500, 1000, -500, 1000], Ok(2000)),
77+
test_large_array: ((0..1000).collect::<Vec<_>>(), Ok(499500)),
78+
test_large_negative_array: ((0..1000).map(|x| -x).collect::<Vec<_>>(), Ok(0)),
79+
test_single_large_positive: (vec![1000000], Ok(1000000)),
80+
test_single_large_negative: (vec![-1000000], Ok(-1000000)),
6181
}
6282
}

src/string/hamming_distance.rs

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1-
pub fn hamming_distance(string_a: &str, string_b: &str) -> usize {
1+
/// Error type for Hamming distance calculation.
2+
#[derive(Debug, PartialEq)]
3+
pub enum HammingDistanceError {
4+
InputStringsHaveDifferentLength,
5+
}
6+
7+
/// Calculates the Hamming distance between two strings.
8+
///
9+
/// The Hamming distance is defined as the number of positions at which the corresponding characters of the two strings are different.
10+
pub fn hamming_distance(string_a: &str, string_b: &str) -> Result<usize, HammingDistanceError> {
211
if string_a.len() != string_b.len() {
3-
panic!("Strings must have the same length");
12+
return Err(HammingDistanceError::InputStringsHaveDifferentLength);
413
}
514

6-
string_a
15+
let distance = string_a
716
.chars()
817
.zip(string_b.chars())
918
.filter(|(a, b)| a != b)
10-
.count()
19+
.count();
20+
21+
Ok(distance)
1122
}
1223

1324
#[cfg(test)]
@@ -16,30 +27,31 @@ mod tests {
1627

1728
macro_rules! test_hamming_distance {
1829
($($name:ident: $tc:expr,)*) => {
19-
$(
20-
#[test]
21-
fn $name() {
22-
let (str_a, str_b, expected) = $tc;
23-
assert_eq!(hamming_distance(str_a, str_b), expected);
24-
assert_eq!(hamming_distance(str_b, str_a), expected);
25-
}
26-
)*
30+
$(
31+
#[test]
32+
fn $name() {
33+
let (str_a, str_b, expected) = $tc;
34+
assert_eq!(hamming_distance(str_a, str_b), expected);
35+
assert_eq!(hamming_distance(str_b, str_a), expected);
36+
}
37+
)*
2738
}
2839
}
2940

3041
test_hamming_distance! {
31-
empty_inputs: ("", "", 0),
32-
length_1_inputs: ("a", "a", 0),
33-
same_strings: ("rust", "rust", 0),
34-
regular_input_0: ("karolin", "kathrin", 3),
35-
regular_input_1: ("kathrin", "kerstin", 4),
36-
regular_input_2: ("00000", "11111", 5),
37-
different_case: ("x", "X", 1),
38-
}
39-
40-
#[test]
41-
#[should_panic]
42-
fn panic_when_inputs_are_of_different_length() {
43-
hamming_distance("0", "");
42+
empty_inputs: ("", "", Ok(0)),
43+
different_length: ("0", "", Err(HammingDistanceError::InputStringsHaveDifferentLength)),
44+
length_1_inputs_identical: ("a", "a", Ok(0)),
45+
length_1_inputs_different: ("a", "b", Ok(1)),
46+
same_strings: ("rust", "rust", Ok(0)),
47+
regular_input_0: ("karolin", "kathrin", Ok(3)),
48+
regular_input_1: ("kathrin", "kerstin", Ok(4)),
49+
regular_input_2: ("00000", "11111", Ok(5)),
50+
different_case: ("x", "X", Ok(1)),
51+
strings_with_no_common_chars: ("abcd", "wxyz", Ok(4)),
52+
long_strings_one_diff: (&"a".repeat(1000), &("a".repeat(999) + "b"), Ok(1)),
53+
long_strings_many_diffs: (&("a".repeat(500) + &"b".repeat(500)), &("b".repeat(500) + &"a".repeat(500)), Ok(1000)),
54+
strings_with_special_chars_identical: ("!@#$%^", "!@#$%^", Ok(0)),
55+
strings_with_special_chars_diff: ("!@#$%^", "&*()_+", Ok(6)),
4456
}
4557
}

0 commit comments

Comments
 (0)