From d1e66b7d1274fbb5b4069438ba47bef62143fd4b Mon Sep 17 00:00:00 2001 From: Nikhil Mitra Date: Mon, 24 Mar 2025 20:52:20 -0400 Subject: [PATCH 1/3] feat: Add rust code for backtracking problems --- rust/Backtracking/combinations_of_sum_k.rs | 41 ++++++++++++++ rust/Backtracking/find_all_permutations.rs | 37 +++++++++++++ rust/Backtracking/find_all_subsets.rs | 32 +++++++++++ rust/Backtracking/n_queens.rs | 54 +++++++++++++++++++ .../Backtracking/phone_keypad_combinations.rs | 54 +++++++++++++++++++ 5 files changed, 218 insertions(+) create mode 100644 rust/Backtracking/combinations_of_sum_k.rs create mode 100644 rust/Backtracking/find_all_permutations.rs create mode 100644 rust/Backtracking/find_all_subsets.rs create mode 100644 rust/Backtracking/n_queens.rs create mode 100644 rust/Backtracking/phone_keypad_combinations.rs diff --git a/rust/Backtracking/combinations_of_sum_k.rs b/rust/Backtracking/combinations_of_sum_k.rs new file mode 100644 index 0000000..32984c6 --- /dev/null +++ b/rust/Backtracking/combinations_of_sum_k.rs @@ -0,0 +1,41 @@ +pub fn combinations_of_sum_k(nums: Vec, target: i32) -> Vec> { + let mut result: Vec> = Vec::new(); + let mut combination: Vec = Vec::new(); + + combinations_of_sum_k_impl(&mut combination, 0, &nums, target, &mut result); + + result +} + +fn combinations_of_sum_k_impl( + combination: &mut Vec, + start_index: usize, + nums: &Vec, + target: i32, + result: &mut Vec> +) { + // Termination condition: If the target is equal to 0, we found a combination + // that sums to 'k'. + if target == 0 { + result.push(combination.clone()); + return; + } + + // Termination condition: If the target is less than 0, no more valid + // combinations can be created by adding it to the current combination. + if target < 0 { + return; + } + + // Starting from start_index, explore all combinations after adding nums[i]. + for i in start_index..nums.len() { + // Add the current number to create a new combination. + combination.push(nums[i]); + + // Recursively explore all paths that branch from this new combination. + combinations_of_sum_k_impl(combination, i, nums, target - nums[i], result); + + // Backtrack by removing the number we just added. + combination.pop(); + } +} \ No newline at end of file diff --git a/rust/Backtracking/find_all_permutations.rs b/rust/Backtracking/find_all_permutations.rs new file mode 100644 index 0000000..d6a73f2 --- /dev/null +++ b/rust/Backtracking/find_all_permutations.rs @@ -0,0 +1,37 @@ +pub fn find_all_permutations(nums: Vec) -> Vec> { + let mut result: Vec> = Vec::new(); + let mut candidate: Vec = Vec::new(); + let mut used: std::collections::HashSet = std::collections::HashSet::new(); + + find_all_permutations_impl(&nums, &mut candidate, &mut used, &mut result); + + result +} + +fn find_all_permutations_impl( + nums: &Vec, + candidate: &mut Vec, + used: &mut std::collections::HashSet, + result: &mut Vec> +) { + // If the current candidate is a complete permutation, add it to the result. + if candidate.len() == nums.len() { + result.push(candidate.clone()); + return; + } + + for &num in nums { + if !used.contains(&num) { + // Add 'num' to the current permutation and mark it as used. + candidate.push(num); + used.insert(num); + + // Recursively explore all branches using the updated permutation candidate. + find_all_permutations_impl(nums, candidate, used, result); + + // Backtrack by reversing the changes made. + candidate.pop(); + used.remove(&num); + } + } +} diff --git a/rust/Backtracking/find_all_subsets.rs b/rust/Backtracking/find_all_subsets.rs new file mode 100644 index 0000000..6c7dbc3 --- /dev/null +++ b/rust/Backtracking/find_all_subsets.rs @@ -0,0 +1,32 @@ +pub fn find_all_subsets(nums: Vec) -> Vec> { + let mut result: Vec> = Vec::new(); + let mut curr_subset: Vec = Vec::new(); + + find_all_subsets_impl(0, &mut curr_subset, &nums, &mut result); + + result +} + +fn find_all_subsets_impl( + i: usize, + curr_subset: &mut Vec, + nums: &Vec, + result: &mut Vec> +) { + // Base case: if all elements have been considered, add the + // current subset to the output. + if i == nums.len() { + result.push(curr_subset.clone()); + return; + } + + // Include the current element and recursively explore all paths + // that branch from this subset. + curr_subset.push(nums[i]); + find_all_subsets_impl(i + 1, curr_subset, nums, result); + + // Exclude the current element and recursively explore all paths + // that branch from this subset. + curr_subset.pop(); + find_all_subsets_impl(i + 1, curr_subset, nums, result); +} diff --git a/rust/Backtracking/n_queens.rs b/rust/Backtracking/n_queens.rs new file mode 100644 index 0000000..c3179d3 --- /dev/null +++ b/rust/Backtracking/n_queens.rs @@ -0,0 +1,54 @@ +pub fn n_queens(n: i32) -> i32 { + let mut result = 0; + let mut diagonals_set = std::collections::HashSet::new(); + let mut anti_diagonals_set = std::collections::HashSet::new(); + let mut cols_set = std::collections::HashSet::new(); + + n_queens_impl(0, &mut diagonals_set, &mut anti_diagonals_set, &mut cols_set, n, &mut result); + + result +} + +fn n_queens_impl( + r: i32, + diagonals_set: &mut std::collections::HashSet, + anti_diagonals_set: &mut std::collections::HashSet, + cols_set: &mut std::collections::HashSet, + n: i32, + result: &mut i32 +) { + // Termination condition: If we have reached the end of the rows, + // we've placed all 'n' queens. + if r == n { + *result += 1; + return; + } + + for c in 0..n { + let curr_diagonal = r - c; + let curr_anti_diagonal = r + c; + + // If there are queens on the current column, diagonal or + // anti-diagonal, skip this square. + if cols_set.contains(&c) || + diagonals_set.contains(&curr_diagonal) || + anti_diagonals_set.contains(&curr_anti_diagonal) { + continue; + } + + // Place the queen by marking the current column, diagonal, and + // anti-diagonal as occupied. + cols_set.insert(c); + diagonals_set.insert(curr_diagonal); + anti_diagonals_set.insert(curr_anti_diagonal); + + // Recursively move to the next row to continue placing queens. + n_queens_impl(r + 1, diagonals_set, anti_diagonals_set, cols_set, n, result); + + // Backtrack by removing the current column, diagonal, and + // anti-diagonal from the hash sets. + cols_set.remove(&c); + diagonals_set.remove(&curr_diagonal); + anti_diagonals_set.remove(&curr_anti_diagonal); + } +} diff --git a/rust/Backtracking/phone_keypad_combinations.rs b/rust/Backtracking/phone_keypad_combinations.rs new file mode 100644 index 0000000..590e987 --- /dev/null +++ b/rust/Backtracking/phone_keypad_combinations.rs @@ -0,0 +1,54 @@ +use std::collections::HashMap; + +pub fn phone_keypad_combinations(digits: String) -> Vec { + if digits.is_empty() { + return Vec::new(); + } + + let mut keypad_map = HashMap::new(); + keypad_map.insert('2', "abc"); + keypad_map.insert('3', "def"); + keypad_map.insert('4', "ghi"); + keypad_map.insert('5', "jkl"); + keypad_map.insert('6', "mno"); + keypad_map.insert('7', "pqrs"); + keypad_map.insert('8', "tuv"); + keypad_map.insert('9', "wxyz"); + + let mut result: Vec = Vec::new(); + let mut curr_combination: Vec = Vec::new(); + + let digits_chars: Vec = digits.chars().collect(); + phone_keypad_combinations_impl(0, &mut curr_combination, &digits_chars, &keypad_map, &mut result); + + result +} + +fn phone_keypad_combinations_impl( + i: usize, + curr_combination: &mut Vec, + digits: &Vec, + keypad_map: &HashMap, + result: &mut Vec +) { + // Termination condition: if all digits have been considered, add the + // current combination to the output list. + if curr_combination.len() == digits.len() { + result.push(curr_combination.iter().collect()); + return; + } + + let digit = digits[i]; + if let Some(letters) = keypad_map.get(&digit) { + for letter in letters.chars() { + // Add the current letter. + curr_combination.push(letter); + + // Recursively explore all paths that branch from this combination. + phone_keypad_combinations_impl(i + 1, curr_combination, digits, keypad_map, result); + + // Backtrack by removing the letter we just added. + curr_combination.pop(); + } + } +} From 8464870be6388d44ced7181d0785643c6da6b210 Mon Sep 17 00:00:00 2001 From: Nikhil Mitra Date: Sun, 30 Mar 2025 09:19:33 -0400 Subject: [PATCH 2/3] feat(rust): Make the rust functions similarly named as their python counterparts --- rust/Backtracking/combinations_of_sum_k.rs | 6 +++--- rust/Backtracking/find_all_permutations.rs | 6 +++--- rust/Backtracking/find_all_subsets.rs | 8 ++++---- rust/Backtracking/n_queens.rs | 6 +++--- rust/Backtracking/phone_keypad_combinations.rs | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/rust/Backtracking/combinations_of_sum_k.rs b/rust/Backtracking/combinations_of_sum_k.rs index 32984c6..c3c71eb 100644 --- a/rust/Backtracking/combinations_of_sum_k.rs +++ b/rust/Backtracking/combinations_of_sum_k.rs @@ -2,12 +2,12 @@ pub fn combinations_of_sum_k(nums: Vec, target: i32) -> Vec> { let mut result: Vec> = Vec::new(); let mut combination: Vec = Vec::new(); - combinations_of_sum_k_impl(&mut combination, 0, &nums, target, &mut result); + dfs(&mut combination, 0, &nums, target, &mut result); result } -fn combinations_of_sum_k_impl( +fn dfs( combination: &mut Vec, start_index: usize, nums: &Vec, @@ -33,7 +33,7 @@ fn combinations_of_sum_k_impl( combination.push(nums[i]); // Recursively explore all paths that branch from this new combination. - combinations_of_sum_k_impl(combination, i, nums, target - nums[i], result); + dfs(combination, i, nums, target - nums[i], result); // Backtrack by removing the number we just added. combination.pop(); diff --git a/rust/Backtracking/find_all_permutations.rs b/rust/Backtracking/find_all_permutations.rs index d6a73f2..706d67c 100644 --- a/rust/Backtracking/find_all_permutations.rs +++ b/rust/Backtracking/find_all_permutations.rs @@ -3,12 +3,12 @@ pub fn find_all_permutations(nums: Vec) -> Vec> { let mut candidate: Vec = Vec::new(); let mut used: std::collections::HashSet = std::collections::HashSet::new(); - find_all_permutations_impl(&nums, &mut candidate, &mut used, &mut result); + dfs(&nums, &mut candidate, &mut used, &mut result); result } -fn find_all_permutations_impl( +fn dfs( nums: &Vec, candidate: &mut Vec, used: &mut std::collections::HashSet, @@ -27,7 +27,7 @@ fn find_all_permutations_impl( used.insert(num); // Recursively explore all branches using the updated permutation candidate. - find_all_permutations_impl(nums, candidate, used, result); + dfs(nums, candidate, used, result); // Backtrack by reversing the changes made. candidate.pop(); diff --git a/rust/Backtracking/find_all_subsets.rs b/rust/Backtracking/find_all_subsets.rs index 6c7dbc3..d13adc2 100644 --- a/rust/Backtracking/find_all_subsets.rs +++ b/rust/Backtracking/find_all_subsets.rs @@ -2,12 +2,12 @@ pub fn find_all_subsets(nums: Vec) -> Vec> { let mut result: Vec> = Vec::new(); let mut curr_subset: Vec = Vec::new(); - find_all_subsets_impl(0, &mut curr_subset, &nums, &mut result); + backtrack(0, &mut curr_subset, &nums, &mut result); result } -fn find_all_subsets_impl( +fn backtrack( i: usize, curr_subset: &mut Vec, nums: &Vec, @@ -23,10 +23,10 @@ fn find_all_subsets_impl( // Include the current element and recursively explore all paths // that branch from this subset. curr_subset.push(nums[i]); - find_all_subsets_impl(i + 1, curr_subset, nums, result); + backtrack(i + 1, curr_subset, nums, result); // Exclude the current element and recursively explore all paths // that branch from this subset. curr_subset.pop(); - find_all_subsets_impl(i + 1, curr_subset, nums, result); + backtrack(i + 1, curr_subset, nums, result); } diff --git a/rust/Backtracking/n_queens.rs b/rust/Backtracking/n_queens.rs index c3179d3..c2b129d 100644 --- a/rust/Backtracking/n_queens.rs +++ b/rust/Backtracking/n_queens.rs @@ -4,12 +4,12 @@ pub fn n_queens(n: i32) -> i32 { let mut anti_diagonals_set = std::collections::HashSet::new(); let mut cols_set = std::collections::HashSet::new(); - n_queens_impl(0, &mut diagonals_set, &mut anti_diagonals_set, &mut cols_set, n, &mut result); + dfs(0, &mut diagonals_set, &mut anti_diagonals_set, &mut cols_set, n, &mut result); result } -fn n_queens_impl( +fn dfs( r: i32, diagonals_set: &mut std::collections::HashSet, anti_diagonals_set: &mut std::collections::HashSet, @@ -43,7 +43,7 @@ fn n_queens_impl( anti_diagonals_set.insert(curr_anti_diagonal); // Recursively move to the next row to continue placing queens. - n_queens_impl(r + 1, diagonals_set, anti_diagonals_set, cols_set, n, result); + dfs(r + 1, diagonals_set, anti_diagonals_set, cols_set, n, result); // Backtrack by removing the current column, diagonal, and // anti-diagonal from the hash sets. diff --git a/rust/Backtracking/phone_keypad_combinations.rs b/rust/Backtracking/phone_keypad_combinations.rs index 590e987..f072e19 100644 --- a/rust/Backtracking/phone_keypad_combinations.rs +++ b/rust/Backtracking/phone_keypad_combinations.rs @@ -19,12 +19,12 @@ pub fn phone_keypad_combinations(digits: String) -> Vec { let mut curr_combination: Vec = Vec::new(); let digits_chars: Vec = digits.chars().collect(); - phone_keypad_combinations_impl(0, &mut curr_combination, &digits_chars, &keypad_map, &mut result); + backtrack(0, &mut curr_combination, &digits_chars, &keypad_map, &mut result); result } -fn phone_keypad_combinations_impl( +fn backtrack( i: usize, curr_combination: &mut Vec, digits: &Vec, @@ -45,7 +45,7 @@ fn phone_keypad_combinations_impl( curr_combination.push(letter); // Recursively explore all paths that branch from this combination. - phone_keypad_combinations_impl(i + 1, curr_combination, digits, keypad_map, result); + backtrack(i + 1, curr_combination, digits, keypad_map, result); // Backtrack by removing the letter we just added. curr_combination.pop(); From 997c71d196057396a977b165a0ce74632a01fc5a Mon Sep 17 00:00:00 2001 From: Nikhil Mitra Date: Mon, 31 Mar 2025 17:53:32 -0400 Subject: [PATCH 3/3] feat(rust): Make sure all variables in the rust Backtracking solutions match python --- rust/Backtracking/combinations_of_sum_k.rs | 12 ++++++------ rust/Backtracking/find_all_permutations.rs | 14 +++++++------- rust/Backtracking/find_all_subsets.rs | 14 +++++++------- rust/Backtracking/n_queens.rs | 12 ++++++------ rust/Backtracking/phone_keypad_combinations.rs | 12 ++++++------ 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/rust/Backtracking/combinations_of_sum_k.rs b/rust/Backtracking/combinations_of_sum_k.rs index c3c71eb..4f2894d 100644 --- a/rust/Backtracking/combinations_of_sum_k.rs +++ b/rust/Backtracking/combinations_of_sum_k.rs @@ -1,10 +1,10 @@ pub fn combinations_of_sum_k(nums: Vec, target: i32) -> Vec> { - let mut result: Vec> = Vec::new(); + let mut res: Vec> = Vec::new(); let mut combination: Vec = Vec::new(); - dfs(&mut combination, 0, &nums, target, &mut result); + dfs(&mut combination, 0, &nums, target, &mut res); - result + res } fn dfs( @@ -12,12 +12,12 @@ fn dfs( start_index: usize, nums: &Vec, target: i32, - result: &mut Vec> + res: &mut Vec> ) { // Termination condition: If the target is equal to 0, we found a combination // that sums to 'k'. if target == 0 { - result.push(combination.clone()); + res.push(combination.clone()); return; } @@ -33,7 +33,7 @@ fn dfs( combination.push(nums[i]); // Recursively explore all paths that branch from this new combination. - dfs(combination, i, nums, target - nums[i], result); + dfs(combination, i, nums, target - nums[i], res); // Backtrack by removing the number we just added. combination.pop(); diff --git a/rust/Backtracking/find_all_permutations.rs b/rust/Backtracking/find_all_permutations.rs index 706d67c..4a16eea 100644 --- a/rust/Backtracking/find_all_permutations.rs +++ b/rust/Backtracking/find_all_permutations.rs @@ -1,22 +1,22 @@ pub fn find_all_permutations(nums: Vec) -> Vec> { - let mut result: Vec> = Vec::new(); + let mut res: Vec> = Vec::new(); let mut candidate: Vec = Vec::new(); let mut used: std::collections::HashSet = std::collections::HashSet::new(); - dfs(&nums, &mut candidate, &mut used, &mut result); + backtrack(&nums, &mut candidate, &mut used, &mut res); - result + res } -fn dfs( +fn backtrack( nums: &Vec, candidate: &mut Vec, used: &mut std::collections::HashSet, - result: &mut Vec> + res: &mut Vec> ) { // If the current candidate is a complete permutation, add it to the result. if candidate.len() == nums.len() { - result.push(candidate.clone()); + res.push(candidate.clone()); return; } @@ -27,7 +27,7 @@ fn dfs( used.insert(num); // Recursively explore all branches using the updated permutation candidate. - dfs(nums, candidate, used, result); + backtrack(nums, candidate, used, res); // Backtrack by reversing the changes made. candidate.pop(); diff --git a/rust/Backtracking/find_all_subsets.rs b/rust/Backtracking/find_all_subsets.rs index d13adc2..2cff516 100644 --- a/rust/Backtracking/find_all_subsets.rs +++ b/rust/Backtracking/find_all_subsets.rs @@ -1,32 +1,32 @@ pub fn find_all_subsets(nums: Vec) -> Vec> { - let mut result: Vec> = Vec::new(); + let mut res: Vec> = Vec::new(); let mut curr_subset: Vec = Vec::new(); - backtrack(0, &mut curr_subset, &nums, &mut result); + backtrack(0, &mut curr_subset, &nums, &mut res); - result + res } fn backtrack( i: usize, curr_subset: &mut Vec, nums: &Vec, - result: &mut Vec> + res: &mut Vec> ) { // Base case: if all elements have been considered, add the // current subset to the output. if i == nums.len() { - result.push(curr_subset.clone()); + res.push(curr_subset.clone()); 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, result); + 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, result); + backtrack(i + 1, curr_subset, nums, res); } diff --git a/rust/Backtracking/n_queens.rs b/rust/Backtracking/n_queens.rs index c2b129d..e62144d 100644 --- a/rust/Backtracking/n_queens.rs +++ b/rust/Backtracking/n_queens.rs @@ -1,12 +1,12 @@ pub fn n_queens(n: i32) -> i32 { - let mut result = 0; + let mut res = 0; let mut diagonals_set = std::collections::HashSet::new(); let mut anti_diagonals_set = std::collections::HashSet::new(); let mut cols_set = std::collections::HashSet::new(); - dfs(0, &mut diagonals_set, &mut anti_diagonals_set, &mut cols_set, n, &mut result); + dfs(0, &mut diagonals_set, &mut anti_diagonals_set, &mut cols_set, n, &mut res); - result + res } fn dfs( @@ -15,12 +15,12 @@ fn dfs( anti_diagonals_set: &mut std::collections::HashSet, cols_set: &mut std::collections::HashSet, n: i32, - result: &mut i32 + res: &mut i32 ) { // Termination condition: If we have reached the end of the rows, // we've placed all 'n' queens. if r == n { - *result += 1; + *res += 1; return; } @@ -43,7 +43,7 @@ fn dfs( anti_diagonals_set.insert(curr_anti_diagonal); // Recursively move to the next row to continue placing queens. - dfs(r + 1, diagonals_set, anti_diagonals_set, cols_set, n, result); + dfs(r + 1, diagonals_set, anti_diagonals_set, cols_set, n, res); // Backtrack by removing the current column, diagonal, and // anti-diagonal from the hash sets. diff --git a/rust/Backtracking/phone_keypad_combinations.rs b/rust/Backtracking/phone_keypad_combinations.rs index f072e19..23cc044 100644 --- a/rust/Backtracking/phone_keypad_combinations.rs +++ b/rust/Backtracking/phone_keypad_combinations.rs @@ -15,13 +15,13 @@ pub fn phone_keypad_combinations(digits: String) -> Vec { keypad_map.insert('8', "tuv"); keypad_map.insert('9', "wxyz"); - let mut result: Vec = Vec::new(); + let mut res: Vec = Vec::new(); let mut curr_combination: Vec = Vec::new(); let digits_chars: Vec = digits.chars().collect(); - backtrack(0, &mut curr_combination, &digits_chars, &keypad_map, &mut result); + backtrack(0, &mut curr_combination, &digits_chars, &keypad_map, &mut res); - result + res } fn backtrack( @@ -29,12 +29,12 @@ fn backtrack( curr_combination: &mut Vec, digits: &Vec, keypad_map: &HashMap, - result: &mut Vec + 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() { - result.push(curr_combination.iter().collect()); + res.push(curr_combination.iter().collect()); return; } @@ -45,7 +45,7 @@ fn backtrack( curr_combination.push(letter); // Recursively explore all paths that branch from this combination. - backtrack(i + 1, curr_combination, digits, keypad_map, result); + backtrack(i + 1, curr_combination, digits, keypad_map, res); // Backtrack by removing the letter we just added. curr_combination.pop();