From cf546bd463a42acd265fd4cbcd35b2abf1bee3e6 Mon Sep 17 00:00:00 2001 From: Joshua Ford Date: Thu, 1 Sep 2022 09:51:03 -0500 Subject: [PATCH] Improve Two Sum example (#365) --- src/general/two_sum.rs | 68 +++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/src/general/two_sum.rs b/src/general/two_sum.rs index 0cb2af29486..3c82ab8f5a8 100644 --- a/src/general/two_sum.rs +++ b/src/general/two_sum.rs @@ -1,24 +1,47 @@ use std::collections::HashMap; -use std::convert::TryInto; - -// Given an array of integers nums and an integer target, -// return indices of the two numbers such that they add up to target. - -pub fn two_sum(nums: Vec, target: i32) -> Vec { - let mut hash_map: HashMap = HashMap::new(); - - for (i, item) in nums.iter().enumerate() { - match hash_map.get(&(target - item)) { - Some(value) => { - return vec![i.try_into().unwrap(), *value]; - } - None => { - hash_map.insert(*item, i.try_into().unwrap()); - } - } + +/// Given an array of integers nums and an integer target, +/// return indices of the two numbers such that they add up to target. +/// +/// # Parameters +/// +/// - `nums`: A list of numbers to check. +/// - `target`: The target sum. +/// +/// # Returns +/// +/// If the target sum is found in the array, the indices of the augend and +/// addend are returned as a tuple. +/// +/// If the target sum cannot be found in the array, `None` is returned. +/// +pub fn two_sum(nums: Vec, target: i32) -> Option<(usize, usize)> { + // This HashMap is used to look up a corresponding index in the `nums` list. + // Given that we know where we are at in the array, we can look up our + // complementary value using this table and only go through the list once. + // + // We populate this table with distances from the target. As we go through + // the list, a distance is computed like so: + // + // `target - current_value` + // + // This distance also tells us about the complementary value we're looking + // for in the array. If we don't find that value, we insert `current_value` + // into the table for future look-ups. As we iterate through the list, + // the number we just inserted might be the perfect distance for another + // number, and we've found a match! + // + let mut distance_table: HashMap = HashMap::new(); + + for (i, current_value) in nums.iter().enumerate() { + match distance_table.get(&(target - current_value)) { + Some(j) => return Some((i, *j)), + _ => distance_table.insert(*current_value, i), + }; } - vec![] + // No match was found! + None } #[cfg(test)] @@ -28,12 +51,15 @@ mod test { #[test] fn test() { let nums = vec![2, 7, 11, 15]; - assert_eq!(two_sum(nums, 9), vec![1, 0]); + assert_eq!(two_sum(nums, 9), Some((1, 0))); let nums = vec![3, 2, 4]; - assert_eq!(two_sum(nums, 6), vec![2, 1]); + assert_eq!(two_sum(nums, 6), Some((2, 1))); let nums = vec![3, 3]; - assert_eq!(two_sum(nums, 6), vec![1, 0]); + assert_eq!(two_sum(nums, 6), Some((1, 0))); + + let nums = vec![2, 7, 11, 15]; + assert_eq!(two_sum(nums, 16), None); } }