Pair Sum - Unsorted

  • Here the list is unsorted
    • see 01two_pointers\12_pair_sumsorted.ipynb
  • Given an array and a target sum, return the indexes of any pair of numbers that add up to the target sum.
  • Avoid brute force with 2 nested loops O(n²) and use the two pointers technique
  • Avoid sorting the array because O(nlogn)

The point:

  • complement of x is y = target - x
  • look for indices NOT for the values by themselves
    • pass 1 = fill a hash map with for each val its index
    • pass 2 = look for each val, if it scomplement is in the hash map

Complexity Analysis :

One pass

Time Space
O(n) O(n)
  • Time, because we go through le list only once
  • Space, the hash map can grow up to n

About Rust :

  • use std::collections::HashMap; my_hashmap.insert(key, value);
  • for (i, &num) in nums.iter().enumerate()
    • .iter() provides immutable references to the elements &T
    • nums remains available afterwards (not consumed)
  • if let Some(&my_value) = my_hash_map.get(&my_key)
  • YES : tested on the Rust Playground

Two passes

use std::collections::HashMap;

fn pair_sum_unsorted_two_pass(nums: &[i32], target: i32) -> Option<(usize, usize)> {
    
    let mut num_to_index = HashMap::new();

    // First pass: fill the hash map with `num` as the key and its index `i` as the value
    for (i, &num) in nums.iter().enumerate() {
        num_to_index.insert(num, i);
    }

    // Second pass: for each number, check if its complement exists in the map and is at a different index
    for (i, &num) in nums.iter().enumerate() {
        let complement = target - num;

        // If the complement is in the hash map and its index is different from `i`, returns the pair
        if let Some(&j) = num_to_index.get(&complement) {
            if i != j {
                return Some((i, j));
            }
        }
    }

    // No valid pair found
    None
}

// fn main(){     // no main() if this code runs in a Jupyter cell 
    println!("{:?}", pair_sum_unsorted_two_pass(&[5, 2, 3, 4, 1], 42));  // () 
    println!("{:?}", pair_sum_unsorted_two_pass(&[5, 2, 3, 4, 1], 6));  // (0,4) 
    let bob = vec![5, 2, 3, 4, 1];    
    println!("{:?}", pair_sum_unsorted_two_pass(&bob, 6));  // (0, 4)
// }
    
None
Some((0, 4))
Some((0, 4))

One pass

  • We can have one pass if we fill the hash map and look for the complement at the same time
  • Preferred solution?
use std::collections::HashMap;

fn pair_sum_unsorted_one_pass(nums: &[i32], target: i32) -> Option<(usize, usize)> {
    
    let mut complement_to_index = HashMap::new();

    for (i, &num) in nums.iter().enumerate() {
        let complement = target - num;
        if let Some(&j) = complement_to_index.get(&complement) {
            return Some((j, i));
        }
        complement_to_index.insert(num, i);
    }
    None
}

// fn main() {
    println!("{:?}", pair_sum_unsorted_one_pass(&[1, 2, 3, 4, 5], 6));  // Some((1, 3))
    println!("{:?}", pair_sum_unsorted_one_pass(&[1, 2, 3, 4, 5], 42)); // None
    let bob = vec![1, 2, 3, 4, 5];    
    println!("{:?}", pair_sum_unsorted_one_pass(&bob, 6));  // (0, 4)
// }
Some((1, 3))
None
Some((0, 4))

V3

  • A more functional way?
use std::collections::HashMap;

fn pair_sum_unsorted_one_pass(nums: &[i32], target: i32) -> Option<(usize, usize)> {
    
    let mut seen = HashMap::new();

    nums.iter().enumerate().find_map(|(i, &num)| {
        let complement = target - num;
        seen.get(&complement).map(|&j| (j, i)).or_else(|| {
            seen.insert(num, i);
            None
        })
    })
}

// fn main() { // no main() if this code runs in a Jupyter cell 
    println!("{:?}", pair_sum_unsorted_one_pass(&[1, 2, 3, 4, 5], 6));  // Some((1, 3))
    println!("{:?}", pair_sum_unsorted_one_pass(&[1, 2, 3, 4, 5], 42)); // None
    let bob = vec![1, 2, 3, 4, 5];    
    println!("{:?}", pair_sum_unsorted_one_pass(&bob, 6));  // Some((1, 3))
// }
Some((1, 3))
None
Some((0, 4))

Back to top

Published on: Jun 22 2025 at 09:00 AM | Last updated: Jun 22 2025 at 09:00 AM

Copyright © 1964-2025 - 40tude