diff --git a/codes/rust/Cargo.toml b/codes/rust/Cargo.toml index 760eedc18..a246eefca 100644 --- a/codes/rust/Cargo.toml +++ b/codes/rust/Cargo.toml @@ -22,7 +22,7 @@ path = "chapter_computational_complexity/space_complexity.rs" # Run Command: cargo run --bin two_sum [[bin]] name = "two_sum" -path = "chapter_computational_complexity/two_sum.rs" +path = "chapter_searching/two_sum.rs" # Run Command: cargo run --bin array [[bin]] @@ -194,5 +194,20 @@ path = "chapter_dynamic_programming/climbing_stairs_constraint_dp.rs" name = "climbing_stairs_backtrack" path = "chapter_dynamic_programming/climbing_stairs_backtrack.rs" +# Run Command: cargo run --bin subset_sum_i_naive +[[bin]] +name = "subset_sum_i_naive" +path = "chapter_backtracking/subset_sum_i_naive.rs" + +# Run Command: cargo run --bin subset_sum_i +[[bin]] +name = "subset_sum_i" +path = "chapter_backtracking/subset_sum_i.rs" + +# Run Command: cargo run --bin subset_sum_ii +[[bin]] +name = "subset_sum_ii" +path = "chapter_backtracking/subset_sum_ii.rs" + [dependencies] rand = "0.8.5" diff --git a/codes/rust/chapter_backtracking/subset_sum_i.rs b/codes/rust/chapter_backtracking/subset_sum_i.rs new file mode 100644 index 000000000..1164846ba --- /dev/null +++ b/codes/rust/chapter_backtracking/subset_sum_i.rs @@ -0,0 +1,50 @@ +/* + * File: subset_sum_i.rs + * Created Time: 2023-07-09 + * Author: sjinzh (sjinzh@gmail.com) + */ + +/* 回溯算法:子集和 I */ +fn backtrack(mut state: Vec, target: i32, choices: &[i32], start: usize, res: &mut Vec>) { + // 子集和等于 target 时,记录解 + if target == 0 { + res.push(state); + return; + } + // 遍历所有选择 + // 剪枝二:从 start 开始遍历,避免生成重复子集 + for i in start..choices.len() { + // 剪枝一:若子集和超过 target ,则直接结束循环 + // 这是因为数组已排序,后边元素更大,子集和一定超过 target + if target - choices[i] < 0 { + break; + } + // 尝试:做出选择,更新 target, start + state.push(choices[i]); + // 进行下一轮选择 + backtrack(state.clone(), target - choices[i], choices, i, res); + // 回退:撤销选择,恢复到之前的状态 + state.pop(); + } +} + +/* 求解子集和 I */ +fn subset_sum_i(nums: &mut [i32], target: i32) -> Vec> { + let state = Vec::new(); // 状态(子集) + nums.sort(); // 对 nums 进行排序 + let start = 0; // 遍历起始点 + let mut res = Vec::new(); + backtrack(state, target, nums, start, &mut res); + res +} + +/* Driver Code */ +pub fn main() { + let mut nums = [ 3, 4, 5 ]; + let target = 9; + + let res = subset_sum_i(&mut nums, target); + + println!("输入数组 nums = {:?}, target = {}", &nums, target); + println!("所有和等于 {} 的子集 res = {:?}", target, &res); +} \ No newline at end of file diff --git a/codes/rust/chapter_backtracking/subset_sum_i_naive.rs b/codes/rust/chapter_backtracking/subset_sum_i_naive.rs new file mode 100644 index 000000000..73ba04ae4 --- /dev/null +++ b/codes/rust/chapter_backtracking/subset_sum_i_naive.rs @@ -0,0 +1,48 @@ +/* + * File: subset_sum_i_naive.rs + * Created Time: 2023-07-09 + * Author: sjinzh (sjinzh@gmail.com) + */ + +/* 回溯算法:子集和 I */ +fn backtrack(mut state: Vec, target: i32, total: i32, choices: &[i32], res: &mut Vec>) { + // 子集和等于 target 时,记录解 + if total == target { + res.push(state); + return; + } + // 遍历所有选择 + for i in 0..choices.len() { + // 剪枝:若子集和超过 target ,则跳过该选择 + if total + choices[i] > target { + continue; + } + // 尝试:做出选择,更新元素和 total + state.push(choices[i]); + // 进行下一轮选择 + backtrack(state.clone(), target, total + choices[i], choices, res); + // 回退:撤销选择,恢复到之前的状态 + state.pop(); + } +} + +/* 求解子集和 I(包含重复子集) */ +fn subset_sum_i_naive(nums: &[i32], target: i32) -> Vec> { + let state = Vec::new(); // 状态(子集) + let total = 0; + let mut res = Vec::new(); + backtrack(state, target, total, nums, &mut res); + res +} + +/* Driver Code */ +pub fn main() { + let nums = [ 3, 4, 5 ]; + let target = 9; + + let res = subset_sum_i_naive(&nums, target); + + println!("输入数组 nums = {:?}, target = {}", &nums, target); + println!("所有和等于 {} 的子集 res = {:?}", target, &res); + println!("请注意,该方法输出的结果包含重复集合"); +} \ No newline at end of file diff --git a/codes/rust/chapter_backtracking/subset_sum_ii.rs b/codes/rust/chapter_backtracking/subset_sum_ii.rs new file mode 100644 index 000000000..f591d68b4 --- /dev/null +++ b/codes/rust/chapter_backtracking/subset_sum_ii.rs @@ -0,0 +1,55 @@ +/* + * File: subset_sum_ii.rs + * Created Time: 2023-07-09 + * Author: sjinzh (sjinzh@gmail.com) + */ + +/* 回溯算法:子集和 II */ +fn backtrack(mut state: Vec, target: i32, choices: &[i32], start: usize, res: &mut Vec>) { + // 子集和等于 target 时,记录解 + if target == 0 { + res.push(state); + return; + } + // 遍历所有选择 + // 剪枝二:从 start 开始遍历,避免生成重复子集 + // 剪枝三:从 start 开始遍历,避免重复选择同一元素 + for i in start..choices.len() { + // 剪枝一:若子集和超过 target ,则直接结束循环 + // 这是因为数组已排序,后边元素更大,子集和一定超过 target + if target - choices[i] < 0 { + break; + } + // 剪枝四:如果该元素与左边元素相等,说明该搜索分支重复,直接跳过 + if i > start && choices[i] == choices[i - 1] { + continue; + } + // 尝试:做出选择,更新 target, start + state.push(choices[i]); + // 进行下一轮选择 + backtrack(state.clone(), target - choices[i], choices, i, res); + // 回退:撤销选择,恢复到之前的状态 + state.pop(); + } +} + +/* 求解子集和 II */ +fn subset_sum_ii(nums: &mut [i32], target: i32) -> Vec> { + let state = Vec::new(); // 状态(子集) + nums.sort(); // 对 nums 进行排序 + let start = 0; // 遍历起始点 + let mut res = Vec::new(); + backtrack(state, target, nums, start, &mut res); + res +} + +/* Driver Code */ +pub fn main() { + let mut nums = [ 4, 4, 5 ]; + let target = 9; + + let res = subset_sum_ii(&mut nums, target); + + println!("输入数组 nums = {:?}, target = {}", &nums, target); + println!("所有和等于 {} 的子集 res = {:?}", target, &res); +}