Skip to content

Commit d1e66b7

Browse files
committed
feat: Add rust code for backtracking problems
1 parent 5feba01 commit d1e66b7

File tree

5 files changed

+218
-0
lines changed

5 files changed

+218
-0
lines changed
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
pub fn combinations_of_sum_k(nums: Vec<i32>, target: i32) -> Vec<Vec<i32>> {
2+
let mut result: Vec<Vec<i32>> = Vec::new();
3+
let mut combination: Vec<i32> = Vec::new();
4+
5+
combinations_of_sum_k_impl(&mut combination, 0, &nums, target, &mut result);
6+
7+
result
8+
}
9+
10+
fn combinations_of_sum_k_impl(
11+
combination: &mut Vec<i32>,
12+
start_index: usize,
13+
nums: &Vec<i32>,
14+
target: i32,
15+
result: &mut Vec<Vec<i32>>
16+
) {
17+
// Termination condition: If the target is equal to 0, we found a combination
18+
// that sums to 'k'.
19+
if target == 0 {
20+
result.push(combination.clone());
21+
return;
22+
}
23+
24+
// Termination condition: If the target is less than 0, no more valid
25+
// combinations can be created by adding it to the current combination.
26+
if target < 0 {
27+
return;
28+
}
29+
30+
// Starting from start_index, explore all combinations after adding nums[i].
31+
for i in start_index..nums.len() {
32+
// Add the current number to create a new combination.
33+
combination.push(nums[i]);
34+
35+
// Recursively explore all paths that branch from this new combination.
36+
combinations_of_sum_k_impl(combination, i, nums, target - nums[i], result);
37+
38+
// Backtrack by removing the number we just added.
39+
combination.pop();
40+
}
41+
}
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
pub fn find_all_permutations(nums: Vec<i32>) -> Vec<Vec<i32>> {
2+
let mut result: Vec<Vec<i32>> = Vec::new();
3+
let mut candidate: Vec<i32> = Vec::new();
4+
let mut used: std::collections::HashSet<i32> = std::collections::HashSet::new();
5+
6+
find_all_permutations_impl(&nums, &mut candidate, &mut used, &mut result);
7+
8+
result
9+
}
10+
11+
fn find_all_permutations_impl(
12+
nums: &Vec<i32>,
13+
candidate: &mut Vec<i32>,
14+
used: &mut std::collections::HashSet<i32>,
15+
result: &mut Vec<Vec<i32>>
16+
) {
17+
// If the current candidate is a complete permutation, add it to the result.
18+
if candidate.len() == nums.len() {
19+
result.push(candidate.clone());
20+
return;
21+
}
22+
23+
for &num in nums {
24+
if !used.contains(&num) {
25+
// Add 'num' to the current permutation and mark it as used.
26+
candidate.push(num);
27+
used.insert(num);
28+
29+
// Recursively explore all branches using the updated permutation candidate.
30+
find_all_permutations_impl(nums, candidate, used, result);
31+
32+
// Backtrack by reversing the changes made.
33+
candidate.pop();
34+
used.remove(&num);
35+
}
36+
}
37+
}

rust/Backtracking/find_all_subsets.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
pub fn find_all_subsets(nums: Vec<i32>) -> Vec<Vec<i32>> {
2+
let mut result: Vec<Vec<i32>> = Vec::new();
3+
let mut curr_subset: Vec<i32> = Vec::new();
4+
5+
find_all_subsets_impl(0, &mut curr_subset, &nums, &mut result);
6+
7+
result
8+
}
9+
10+
fn find_all_subsets_impl(
11+
i: usize,
12+
curr_subset: &mut Vec<i32>,
13+
nums: &Vec<i32>,
14+
result: &mut Vec<Vec<i32>>
15+
) {
16+
// Base case: if all elements have been considered, add the
17+
// current subset to the output.
18+
if i == nums.len() {
19+
result.push(curr_subset.clone());
20+
return;
21+
}
22+
23+
// Include the current element and recursively explore all paths
24+
// that branch from this subset.
25+
curr_subset.push(nums[i]);
26+
find_all_subsets_impl(i + 1, curr_subset, nums, result);
27+
28+
// Exclude the current element and recursively explore all paths
29+
// that branch from this subset.
30+
curr_subset.pop();
31+
find_all_subsets_impl(i + 1, curr_subset, nums, result);
32+
}

rust/Backtracking/n_queens.rs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
pub fn n_queens(n: i32) -> i32 {
2+
let mut result = 0;
3+
let mut diagonals_set = std::collections::HashSet::new();
4+
let mut anti_diagonals_set = std::collections::HashSet::new();
5+
let mut cols_set = std::collections::HashSet::new();
6+
7+
n_queens_impl(0, &mut diagonals_set, &mut anti_diagonals_set, &mut cols_set, n, &mut result);
8+
9+
result
10+
}
11+
12+
fn n_queens_impl(
13+
r: i32,
14+
diagonals_set: &mut std::collections::HashSet<i32>,
15+
anti_diagonals_set: &mut std::collections::HashSet<i32>,
16+
cols_set: &mut std::collections::HashSet<i32>,
17+
n: i32,
18+
result: &mut i32
19+
) {
20+
// Termination condition: If we have reached the end of the rows,
21+
// we've placed all 'n' queens.
22+
if r == n {
23+
*result += 1;
24+
return;
25+
}
26+
27+
for c in 0..n {
28+
let curr_diagonal = r - c;
29+
let curr_anti_diagonal = r + c;
30+
31+
// If there are queens on the current column, diagonal or
32+
// anti-diagonal, skip this square.
33+
if cols_set.contains(&c) ||
34+
diagonals_set.contains(&curr_diagonal) ||
35+
anti_diagonals_set.contains(&curr_anti_diagonal) {
36+
continue;
37+
}
38+
39+
// Place the queen by marking the current column, diagonal, and
40+
// anti-diagonal as occupied.
41+
cols_set.insert(c);
42+
diagonals_set.insert(curr_diagonal);
43+
anti_diagonals_set.insert(curr_anti_diagonal);
44+
45+
// Recursively move to the next row to continue placing queens.
46+
n_queens_impl(r + 1, diagonals_set, anti_diagonals_set, cols_set, n, result);
47+
48+
// Backtrack by removing the current column, diagonal, and
49+
// anti-diagonal from the hash sets.
50+
cols_set.remove(&c);
51+
diagonals_set.remove(&curr_diagonal);
52+
anti_diagonals_set.remove(&curr_anti_diagonal);
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use std::collections::HashMap;
2+
3+
pub fn phone_keypad_combinations(digits: String) -> Vec<String> {
4+
if digits.is_empty() {
5+
return Vec::new();
6+
}
7+
8+
let mut keypad_map = HashMap::new();
9+
keypad_map.insert('2', "abc");
10+
keypad_map.insert('3', "def");
11+
keypad_map.insert('4', "ghi");
12+
keypad_map.insert('5', "jkl");
13+
keypad_map.insert('6', "mno");
14+
keypad_map.insert('7', "pqrs");
15+
keypad_map.insert('8', "tuv");
16+
keypad_map.insert('9', "wxyz");
17+
18+
let mut result: Vec<String> = Vec::new();
19+
let mut curr_combination: Vec<char> = Vec::new();
20+
21+
let digits_chars: Vec<char> = digits.chars().collect();
22+
phone_keypad_combinations_impl(0, &mut curr_combination, &digits_chars, &keypad_map, &mut result);
23+
24+
result
25+
}
26+
27+
fn phone_keypad_combinations_impl(
28+
i: usize,
29+
curr_combination: &mut Vec<char>,
30+
digits: &Vec<char>,
31+
keypad_map: &HashMap<char, &str>,
32+
result: &mut Vec<String>
33+
) {
34+
// Termination condition: if all digits have been considered, add the
35+
// current combination to the output list.
36+
if curr_combination.len() == digits.len() {
37+
result.push(curr_combination.iter().collect());
38+
return;
39+
}
40+
41+
let digit = digits[i];
42+
if let Some(letters) = keypad_map.get(&digit) {
43+
for letter in letters.chars() {
44+
// Add the current letter.
45+
curr_combination.push(letter);
46+
47+
// Recursively explore all paths that branch from this combination.
48+
phone_keypad_combinations_impl(i + 1, curr_combination, digits, keypad_map, result);
49+
50+
// Backtrack by removing the letter we just added.
51+
curr_combination.pop();
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)