diff --git a/rust/Backtracking/combination_of_sum.rs b/rust/Backtracking/combination_of_sum.rs new file mode 100644 index 0000000..cb75b36 --- /dev/null +++ b/rust/Backtracking/combination_of_sum.rs @@ -0,0 +1,40 @@ +fn dfs( + combination: &mut Vec, + start_index: usize, + nums: &[u32], + target: u32, + res: &mut Vec>, +) { + // Termination condition: If the target is equal to 0, we found a combination that sums to 'k' + if target == 0 { + res.push(combination.clone()); + return; + } + + // Explore all combinations starting from 'start_index' + for i in start_index..nums.len() { + let num = nums[i]; + + // If current number is greater than the remaining target, no need to proceed (early stopping) + if num > target { + break; // this is where early stop occurs + // since nums are ordered no need to check the others (there are > target) + } + + // Add the current number to create a new combination + combination.push(num); + // Recursively explore all paths that branch from this new combination + dfs(combination, i, nums, target - num, res); // Safe subtraction: target >= num + // Backtrack by removing the number we just added + combination.pop(); + } +} + +fn combinations_of_sum_k(nums: &[u32], target: u32) -> Vec> { + let mut sorted_nums = nums.to_vec(); + sorted_nums.sort_unstable(); // Sort the numbers to allow early stopping + let mut combination = Vec::new(); + let mut res = Vec::new(); + dfs(&mut combination, 0, &sorted_nums, target, &mut res); + res +} diff --git a/rust/Backtracking/find_all_permuations.rs b/rust/Backtracking/find_all_permuations.rs new file mode 100644 index 0000000..261ce3a --- /dev/null +++ b/rust/Backtracking/find_all_permuations.rs @@ -0,0 +1,19 @@ +fn backtrack(nums: &mut Vec, start: usize, res: &mut Vec>) { + // if current candidate is a complete permutation add it to the result + if start == nums.len() { + res.push(nums.clone()); // unavoidable here unless we return Vec<&[i32]> + return; + } + for i in start..nums.len() { + nums.swap(start, i); + backtrack(nums, start + 1, res); + nums.swap(start, i); // backtrack + } +} + +fn find_all_permutations(nums: &[i32]) -> Vec> { + let mut res = Vec::new(); + let mut nums = nums.to_vec(); + backtrack(&mut nums, 0, &mut res); + res +} diff --git a/rust/Backtracking/find_all_subsets.rs b/rust/Backtracking/find_all_subsets.rs new file mode 100644 index 0000000..b0aa1ea --- /dev/null +++ b/rust/Backtracking/find_all_subsets.rs @@ -0,0 +1,19 @@ +fn backtrack(i: usize, curr_subset: &mut Vec, nums: &[i32], res: &mut Vec>) { + // base case : if all elements have been considered, add the current subset to res + if i == nums.len() { + res.push(curr_subset.clone()); // cannot push curr_subset (it is used afterward) so we push a clone of it + return; + } + // include the current element and recursively explore all paths that branch from this subset + curr_subset.push(nums[i]); + backtrack(i + 1, curr_subset, nums, res); + // exclude the current element and recursively explore all paths that branch from this subset + curr_subset.pop(); + backtrack(i + 1, curr_subset, nums, res); +} + +fn find_all_subsets(nums: &[i32]) -> Vec> { + let mut res = Vec::new(); + backtrack(0, &mut vec![], nums, &mut res); + res +} diff --git a/rust/Backtracking/n_queens.rs b/rust/Backtracking/n_queens.rs new file mode 100644 index 0000000..e8045fc --- /dev/null +++ b/rust/Backtracking/n_queens.rs @@ -0,0 +1,57 @@ +use std::collections::HashSet; + +fn dfs( + row: i32, + cols: &mut HashSet, + diagonals: &mut HashSet, + anti_diagonals: &mut HashSet, + n: i32, + count: &mut i32, +) { + // If we reach the end, all queens are placed successfully + if row == n { + *count += 1; + return; + } + + for col in 0..n { + let diag = row - col; + let anti_diag = row + col; + + // Check if the position is safe + if cols.contains(&col) || diagonals.contains(&diag) || anti_diagonals.contains(&anti_diag) { + continue; + } + + // Choose: place the queen + cols.insert(col); + diagonals.insert(diag); + anti_diagonals.insert(anti_diag); + + // Explore + dfs(row + 1, cols, diagonals, anti_diagonals, n, count); + + // Unchoose (backtrack): remove the queen + cols.remove(&col); + diagonals.remove(&diag); + anti_diagonals.remove(&anti_diag); + } +} + +fn n_queens(n: i32) -> i32 { + let mut cols = HashSet::new(); + let mut diagonals = HashSet::new(); + let mut anti_diagonals = HashSet::new(); + let mut count = 0; + + dfs( + 0, + &mut cols, + &mut diagonals, + &mut anti_diagonals, + n, + &mut count, + ); + + count +} diff --git a/rust/Backtracking/phone_keypad_combinations.rs b/rust/Backtracking/phone_keypad_combinations.rs new file mode 100644 index 0000000..40a2abf --- /dev/null +++ b/rust/Backtracking/phone_keypad_combinations.rs @@ -0,0 +1,56 @@ +use std::collections::HashMap; + +fn backtrack( + i: usize, + curr_combination: &mut Vec, + digits: &[char], + keypad_map: &HashMap, + res: &mut Vec, +) { + // Termination condition: if all digits have been considered + // Add the current combination to the output list + if curr_combination.len() == digits.len() { + res.push(curr_combination.iter().collect()); + return; + } + + // PYTHON = for letter in keypad_map[digits[i]]... + if let Some(&digit) = digits.get(i) { + if let Some(letters) = keypad_map.get(&digit) { + for letter in letters.chars() { + // Add current letter + curr_combination.push(letter); + // Recursively explore all paths that branch from this combination. + backtrack(i + 1, curr_combination, digits, keypad_map, res); + // Backtrack by removing the letter we just added. + curr_combination.pop(); + } + } + } +} + +fn phone_keypad_combinations(digits: &str) -> Vec { + let index = 0; + let mut curr_combination = Vec::new(); + let digits_chars: Vec = digits.chars().collect(); // collect chars once + let keypad_map = HashMap::from([ + ('2', "abc"), + ('3', "def"), + ('4', "ghi"), + ('5', "jkl"), + ('6', "mno"), + ('7', "pqrs"), + ('8', "tuv"), + ('9', "wxyz"), + ]); + let mut res = Vec::new(); + + backtrack( + index, + &mut curr_combination, + &digits_chars, + &keypad_map, + &mut res, + ); + res +}