pub fn min_coins_for_change(coins: &[usize], amount: usize) -> Option<usize> {
if amount == 0 {
return Some(0);
}
if coins.is_empty() {
return None;
}
let mut dp = vec![usize::MAX; amount + 1];
dp[0] = 0;
for &coin in coins {
for curr_amount in coin..=amount {
if dp[curr_amount - coin] != usize::MAX {
dp[curr_amount] = dp[curr_amount].min(dp[curr_amount - coin] + 1);
}
}
}
if dp[amount] == usize::MAX {
None
} else {
Some(dp[amount])
}
}
pub fn count_change_ways(coins: &[usize], amount: usize) -> usize {
let mut dp = vec![0_usize; amount + 1];
dp[0] = 1;
for &coin in coins {
for curr_amount in coin..=amount {
dp[curr_amount] += dp[curr_amount - coin];
}
}
dp[amount]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_min_coins_for_change() {
let coins = vec![1, 6, 10];
assert_eq!(min_coins_for_change(&coins, 18), Some(3));
assert_eq!(min_coins_for_change(&coins, 0), Some(0));
assert_eq!(min_coins_for_change(&coins, 1), Some(1));
let coins2 = vec![2, 4];
assert_eq!(min_coins_for_change(&coins2, 7), None);
}
#[test]
fn test_count_change_ways() {
let coins = vec![1, 2, 5];
assert_eq!(count_change_ways(&coins, 5), 4);
assert_eq!(count_change_ways(&coins, 0), 1);
let coins2 = vec![2, 4];
assert_eq!(count_change_ways(&coins2, 8), 3);
assert_eq!(count_change_ways(&[], 5), 0);
}
}