Skip to content

Commit a8ef47f

Browse files
authored
Merge branch 'master' into optimize-btree-search
2 parents 9e96a3f + 65ca19d commit a8ef47f

File tree

16 files changed

+582
-290
lines changed

16 files changed

+582
-290
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ unwrap_in_result = { level = "allow", priority = 1 }
145145
unwrap_used = { level = "allow", priority = 1 }
146146
use_debug = { level = "allow", priority = 1 }
147147
wildcard_enum_match_arm = { level = "allow", priority = 1 }
148+
renamed_function_params = { level = "allow", priority = 1 }
148149
# nursery-lints:
149150
branches_sharing_code = { level = "allow", priority = 1 }
150151
cognitive_complexity = { level = "allow", priority = 1 }
@@ -160,5 +161,9 @@ redundant_clone = { level = "allow", priority = 1 }
160161
suboptimal_flops = { level = "allow", priority = 1 }
161162
suspicious_operation_groupings = { level = "allow", priority = 1 }
162163
use_self = { level = "allow", priority = 1 }
164+
while_float = { level = "allow", priority = 1 }
165+
needless_pass_by_ref_mut = { level = "allow", priority = 1 }
163166
# cargo-lints:
164167
cargo_common_metadata = { level = "allow", priority = 1 }
168+
# style-lints:
169+
doc_lazy_continuation = { level = "allow", priority = 1 }

DIRECTORY.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* [Parentheses Generator](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/parentheses_generator.rs)
1111
* [Permutations](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/permutations.rs)
1212
* [Rat In Maze](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/rat_in_maze.rs)
13+
* [Subset Sum](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/subset_sum.rs)
1314
* [Sudoku](https://github.com/TheAlgorithms/Rust/blob/master/src/backtracking/sudoku.rs)
1415
* Big Integer
1516
* [Fast Factorial](https://github.com/TheAlgorithms/Rust/blob/master/src/big_integer/fast_factorial.rs)
@@ -62,7 +63,6 @@
6263
* [Graph](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/graph.rs)
6364
* [Hash Table](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/hash_table.rs)
6465
* [Heap](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/heap.rs)
65-
* [Infix To Postfix](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/infix_to_postfix.rs)
6666
* [Lazy Segment Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/lazy_segment_tree.rs)
6767
* [Linked List](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/linked_list.rs)
6868
* [Postfix Evaluation](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/postfix_evaluation.rs)
@@ -155,6 +155,7 @@
155155
* [K Means](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/k_means.rs)
156156
* [Linear Regression](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/linear_regression.rs)
157157
* Loss Function
158+
* [Average Margin Ranking Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/loss_function/average_margin_ranking_loss.rs)
158159
* [Hinge Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/loss_function/hinge_loss.rs)
159160
* [Huber Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/loss_function/huber_loss.rs)
160161
* [Kl Divergence Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/machine_learning/loss_function/kl_divergence_loss.rs)
@@ -201,6 +202,7 @@
201202
* [Geometric Series](https://github.com/TheAlgorithms/Rust/blob/master/src/math/geometric_series.rs)
202203
* [Greatest Common Divisor](https://github.com/TheAlgorithms/Rust/blob/master/src/math/greatest_common_divisor.rs)
203204
* [Huber Loss](https://github.com/TheAlgorithms/Rust/blob/master/src/math/huber_loss.rs)
205+
* [Infix To Postfix](https://github.com/TheAlgorithms/Rust/blob/master/src/math/infix_to_postfix.rs)
204206
* [Interest](https://github.com/TheAlgorithms/Rust/blob/master/src/math/interest.rs)
205207
* [Interpolation](https://github.com/TheAlgorithms/Rust/blob/master/src/math/interpolation.rs)
206208
* [Interquartile Range](https://github.com/TheAlgorithms/Rust/blob/master/src/math/interquartile_range.rs)

src/backtracking/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod n_queens;
66
mod parentheses_generator;
77
mod permutations;
88
mod rat_in_maze;
9+
mod subset_sum;
910
mod sudoku;
1011

1112
pub use all_combination_of_size_k::generate_all_combinations;
@@ -16,4 +17,5 @@ pub use n_queens::n_queens_solver;
1617
pub use parentheses_generator::generate_parentheses;
1718
pub use permutations::permute;
1819
pub use rat_in_maze::find_path_in_maze;
20+
pub use subset_sum::has_subset_with_sum;
1921
pub use sudoku::sudoku_solver;

src/backtracking/subset_sum.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//! This module provides functionality to check if there exists a subset of a given set of integers
2+
//! that sums to a target value. The implementation uses a recursive backtracking approach.
3+
4+
/// Checks if there exists a subset of the given set that sums to the target value.
5+
pub fn has_subset_with_sum(set: &[isize], target: isize) -> bool {
6+
backtrack(set, set.len(), target)
7+
}
8+
9+
fn backtrack(set: &[isize], remaining_items: usize, target: isize) -> bool {
10+
// Found a subset with the required sum
11+
if target == 0 {
12+
return true;
13+
}
14+
// No more elements to process
15+
if remaining_items == 0 {
16+
return false;
17+
}
18+
// Check if we can find a subset including or excluding the last element
19+
backtrack(set, remaining_items - 1, target)
20+
|| backtrack(set, remaining_items - 1, target - set[remaining_items - 1])
21+
}
22+
23+
#[cfg(test)]
24+
mod tests {
25+
use super::*;
26+
27+
macro_rules! has_subset_with_sum_tests {
28+
($($name:ident: $test_case:expr,)*) => {
29+
$(
30+
#[test]
31+
fn $name() {
32+
let (set, target, expected) = $test_case;
33+
assert_eq!(has_subset_with_sum(set, target), expected);
34+
}
35+
)*
36+
}
37+
}
38+
39+
has_subset_with_sum_tests! {
40+
test_small_set_with_sum: (&[3, 34, 4, 12, 5, 2], 9, true),
41+
test_small_set_without_sum: (&[3, 34, 4, 12, 5, 2], 30, false),
42+
test_consecutive_set_with_sum: (&[1, 2, 3, 4, 5, 6], 10, true),
43+
test_consecutive_set_without_sum: (&[1, 2, 3, 4, 5, 6], 22, false),
44+
test_large_set_with_sum: (&[5, 10, 12, 13, 15, 18, -1, 10, 50, -2, 3, 4], 30, true),
45+
test_empty_set: (&[], 0, true),
46+
test_empty_set_with_nonzero_sum: (&[], 10, false),
47+
test_single_element_equal_to_sum: (&[10], 10, true),
48+
test_single_element_not_equal_to_sum: (&[5], 10, false),
49+
test_negative_set_with_sum: (&[-7, -3, -2, 5, 8], 0, true),
50+
test_negative_sum: (&[1, 2, 3, 4, 5], -1, false),
51+
test_negative_sum_with_negatives: (&[-7, -3, -2, 5, 8], -4, true),
52+
test_negative_sum_with_negatives_no_solution: (&[-7, -3, -2, 5, 8], -14, false),
53+
test_even_inputs_odd_target: (&[2, 4, 6, 2, 8, -2, 10, 12, -24, 8, 12, 18], 3, false),
54+
}
55+
}

src/big_integer/fast_factorial.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,19 @@ pub fn fast_factorial(n: usize) -> BigUint {
3030
// get list of primes that will be factors of n!
3131
let primes = sieve_of_eratosthenes(n);
3232

33-
let mut p_indeces = BTreeMap::new();
34-
3533
// Map the primes with their index
36-
primes.into_iter().for_each(|p| {
37-
p_indeces.insert(p, index(p, n));
38-
});
34+
let p_indices = primes
35+
.into_iter()
36+
.map(|p| (p, index(p, n)))
37+
.collect::<BTreeMap<_, _>>();
3938

40-
let max_bits = p_indeces.get(&2).unwrap().next_power_of_two().ilog2() + 1;
39+
let max_bits = p_indices.get(&2).unwrap().next_power_of_two().ilog2() + 1;
4140

4241
// Create a Vec of 1's
43-
let mut a = Vec::with_capacity(max_bits as usize);
44-
a.resize(max_bits as usize, BigUint::one());
42+
let mut a = vec![BigUint::one(); max_bits as usize];
4543

4644
// For every prime p, multiply a[i] by p if the ith bit of p's index is 1
47-
for (p, i) in p_indeces {
45+
for (p, i) in p_indices {
4846
let mut bit = 1usize;
4947
while bit.ilog2() < max_bits {
5048
if (bit & i) > 0 {

src/data_structures/infix_to_postfix.rs

Lines changed: 0 additions & 72 deletions
This file was deleted.

src/data_structures/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ mod floyds_algorithm;
66
pub mod graph;
77
mod hash_table;
88
mod heap;
9-
mod infix_to_postfix;
109
mod lazy_segment_tree;
1110
mod linked_list;
1211
mod postfix_evaluation;
@@ -31,7 +30,6 @@ pub use self::graph::DirectedGraph;
3130
pub use self::graph::UndirectedGraph;
3231
pub use self::hash_table::HashTable;
3332
pub use self::heap::Heap;
34-
pub use self::infix_to_postfix::infix_to_postfix;
3533
pub use self::lazy_segment_tree::LazySegmentTree;
3634
pub use self::linked_list::LinkedList;
3735
pub use self::postfix_evaluation::evaluate_postfix;
Lines changed: 78 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,94 @@
1-
/// Coin change via Dynamic Programming
1+
//! This module provides a solution to the coin change problem using dynamic programming.
2+
//! The `coin_change` function calculates the fewest number of coins required to make up
3+
//! a given amount using a specified set of coin denominations.
4+
//!
5+
//! The implementation leverages dynamic programming to build up solutions for smaller
6+
//! amounts and combines them to solve for larger amounts. It ensures optimal substructure
7+
//! and overlapping subproblems are efficiently utilized to achieve the solution.
28
3-
/// coin_change(coins, amount) returns the fewest number of coins that need to make up that amount.
4-
/// If that amount of money cannot be made up by any combination of the coins, return `None`.
9+
//! # Complexity
10+
//! - Time complexity: O(amount * coins.length)
11+
//! - Space complexity: O(amount)
12+
13+
/// Returns the fewest number of coins needed to make up the given amount using the provided coin denominations.
14+
/// If the amount cannot be made up by any combination of the coins, returns `None`.
15+
///
16+
/// # Arguments
17+
/// * `coins` - A slice of coin denominations.
18+
/// * `amount` - The total amount of money to be made up.
19+
///
20+
/// # Returns
21+
/// * `Option<usize>` - The minimum number of coins required to make up the amount, or `None` if it's not possible.
522
///
6-
/// # Arguments:
7-
/// * `coins` - coins of different denominations
8-
/// * `amount` - a total amount of money be made up.
923
/// # Complexity
10-
/// - time complexity: O(amount * coins.length),
11-
/// - space complexity: O(amount),
24+
/// * Time complexity: O(amount * coins.length)
25+
/// * Space complexity: O(amount)
1226
pub fn coin_change(coins: &[usize], amount: usize) -> Option<usize> {
13-
let mut dp = vec![None; amount + 1];
14-
dp[0] = Some(0);
27+
let mut min_coins = vec![None; amount + 1];
28+
min_coins[0] = Some(0);
1529

16-
// Assume dp[i] is the fewest number of coins making up amount i,
17-
// then for every coin in coins, dp[i] = min(dp[i - coin] + 1).
18-
for i in 0..=amount {
19-
for &coin in coins {
20-
if i >= coin {
21-
dp[i] = match dp[i - coin] {
22-
Some(prev_coins) => match dp[i] {
23-
Some(curr_coins) => Some(curr_coins.min(prev_coins + 1)),
24-
None => Some(prev_coins + 1),
25-
},
26-
None => dp[i],
27-
};
28-
}
29-
}
30-
}
30+
(0..=amount).for_each(|curr_amount| {
31+
coins
32+
.iter()
33+
.filter(|&&coin| curr_amount >= coin)
34+
.for_each(|&coin| {
35+
if let Some(prev_min_coins) = min_coins[curr_amount - coin] {
36+
min_coins[curr_amount] = Some(
37+
min_coins[curr_amount].map_or(prev_min_coins + 1, |curr_min_coins| {
38+
curr_min_coins.min(prev_min_coins + 1)
39+
}),
40+
);
41+
}
42+
});
43+
});
3144

32-
dp[amount]
45+
min_coins[amount]
3346
}
3447

3548
#[cfg(test)]
3649
mod tests {
3750
use super::*;
3851

39-
#[test]
40-
fn basic() {
41-
// 11 = 5 * 2 + 1 * 1
42-
let coins = vec![1, 2, 5];
43-
assert_eq!(Some(3), coin_change(&coins, 11));
44-
45-
// 119 = 11 * 10 + 7 * 1 + 2 * 1
46-
let coins = vec![2, 3, 5, 7, 11];
47-
assert_eq!(Some(12), coin_change(&coins, 119));
48-
}
49-
50-
#[test]
51-
fn coins_empty() {
52-
let coins = vec![];
53-
assert_eq!(None, coin_change(&coins, 1));
54-
}
55-
56-
#[test]
57-
fn amount_zero() {
58-
let coins = vec![1, 2, 3];
59-
assert_eq!(Some(0), coin_change(&coins, 0));
52+
macro_rules! coin_change_tests {
53+
($($name:ident: $test_case:expr,)*) => {
54+
$(
55+
#[test]
56+
fn $name() {
57+
let (coins, amount, expected) = $test_case;
58+
assert_eq!(expected, coin_change(&coins, amount));
59+
}
60+
)*
61+
}
6062
}
6163

62-
#[test]
63-
fn fail_change() {
64-
// 3 can't be change by 2.
65-
let coins = vec![2];
66-
assert_eq!(None, coin_change(&coins, 3));
67-
let coins = vec![10, 20, 50, 100];
68-
assert_eq!(None, coin_change(&coins, 5));
64+
coin_change_tests! {
65+
test_basic_case: (vec![1, 2, 5], 11, Some(3)),
66+
test_multiple_denominations: (vec![2, 3, 5, 7, 11], 119, Some(12)),
67+
test_empty_coins: (vec![], 1, None),
68+
test_zero_amount: (vec![1, 2, 3], 0, Some(0)),
69+
test_no_solution_small_coin: (vec![2], 3, None),
70+
test_no_solution_large_coin: (vec![10, 20, 50, 100], 5, None),
71+
test_single_coin_large_amount: (vec![1], 100, Some(100)),
72+
test_large_amount_multiple_coins: (vec![1, 2, 5], 10000, Some(2000)),
73+
test_no_combination_possible: (vec![3, 7], 5, None),
74+
test_exact_combination: (vec![1, 3, 4], 6, Some(2)),
75+
test_large_denomination_multiple_coins: (vec![10, 50, 100], 1000, Some(10)),
76+
test_small_amount_not_possible: (vec![5, 10], 1, None),
77+
test_non_divisible_amount: (vec![2], 3, None),
78+
test_all_multiples: (vec![1, 2, 4, 8], 15, Some(4)),
79+
test_large_amount_mixed_coins: (vec![1, 5, 10, 25], 999, Some(45)),
80+
test_prime_coins_and_amount: (vec![2, 3, 5, 7], 17, Some(3)),
81+
test_coins_larger_than_amount: (vec![5, 10, 20], 1, None),
82+
test_repeating_denominations: (vec![1, 1, 1, 5], 8, Some(4)),
83+
test_non_standard_denominations: (vec![1, 4, 6, 9], 15, Some(2)),
84+
test_very_large_denominations: (vec![1000, 2000, 5000], 1, None),
85+
test_large_amount_performance: (vec![1, 5, 10, 25, 50, 100, 200, 500], 9999, Some(29)),
86+
test_powers_of_two: (vec![1, 2, 4, 8, 16, 32, 64], 127, Some(7)),
87+
test_fibonacci_sequence: (vec![1, 2, 3, 5, 8, 13, 21, 34], 55, Some(2)),
88+
test_mixed_small_large: (vec![1, 100, 1000, 10000], 11001, Some(3)),
89+
test_impossible_combinations: (vec![2, 4, 6, 8], 7, None),
90+
test_greedy_approach_does_not_work: (vec![1, 12, 20], 24, Some(2)),
91+
test_zero_denominations_no_solution: (vec![0], 1, None),
92+
test_zero_denominations_solution: (vec![0], 0, Some(0)),
6993
}
7094
}

0 commit comments

Comments
 (0)