-
Notifications
You must be signed in to change notification settings - Fork 128
Add Rust Backtracking #89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
fn dfs( | ||
combination: &mut Vec<u32>, | ||
start_index: usize, | ||
nums: &[u32], | ||
target: u32, | ||
res: &mut Vec<Vec<u32>>, | ||
) { | ||
// 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; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
// Explore all combinations starting from 'start_index' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try to keep the comments and the logic structure the same as Python |
||
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<Vec<u32>> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please order this function first, before the dfs function |
||
let mut sorted_nums = nums.to_vec(); | ||
sorted_nums.sort_unstable(); // Sort the numbers to allow early stopping | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove the sorting. We'd like to keep it consistent with the python solutions, which don't do any sorting here. |
||
let mut combination = Vec::new(); | ||
let mut res = Vec::new(); | ||
dfs(&mut combination, 0, &sorted_nums, target, &mut res); | ||
res | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
fn backtrack(nums: &mut Vec<i32>, start: usize, res: &mut Vec<Vec<i32>>) { | ||
// 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<Vec<i32>> { | ||
let mut res = Vec::new(); | ||
let mut nums = nums.to_vec(); | ||
backtrack(&mut nums, 0, &mut res); | ||
res | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
fn backtrack(i: usize, curr_subset: &mut Vec<i32>, nums: &[i32], res: &mut Vec<Vec<i32>>) { | ||
// 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<Vec<i32>> { | ||
let mut res = Vec::new(); | ||
backtrack(0, &mut vec![], nums, &mut res); | ||
res | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
use std::collections::HashSet; | ||
|
||
fn dfs( | ||
row: i32, | ||
cols: &mut HashSet<i32>, | ||
diagonals: &mut HashSet<i32>, | ||
anti_diagonals: &mut HashSet<i32>, | ||
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 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
use std::collections::HashMap; | ||
|
||
fn backtrack( | ||
i: usize, | ||
curr_combination: &mut Vec<char>, | ||
digits: &[char], | ||
keypad_map: &HashMap<char, &str>, | ||
res: &mut Vec<String>, | ||
) { | ||
// 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<String> { | ||
let index = 0; | ||
let mut curr_combination = Vec::new(); | ||
let digits_chars: Vec<char> = 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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
combination_of_sum.rs
->combinations_of_sum_k.rs