90. 子集 II
这一题就是典型的used横向剪枝与index纵向剪枝共同运用的题目
直接看代码:
即与顺序有关,与数也有关,用过的数不能再用了
/// 90. 子集IIpub fn subsets_with_dup(mut nums: Vec<i32>) -> Vec<Vec<i32>> {nums.sort();let mut res: Vec<Vec<i32>> = Vec::new();let mut temp = Vec::new();let mut used = vec![false; nums.len()];Self::dfs(0, &mut nums, &mut res, &mut temp, &mut used);res}fn dfs(cur: usize, nums: &mut Vec<i32>, res: &mut Vec<Vec<i32>>,temp: &mut Vec<i32>, used: &mut Vec<bool>){res.push(temp.clone());if cur == nums.len() {return;}for x in cur..nums.len() {// 横向剪枝if x > 0 && !used[x-1] && nums[x] == nums[x-1] {continue;}used[x] = true;temp.push(nums[x]);// 递归方向剪枝Self::dfs(x + 1, nums, res, temp, used);temp.pop();used[x] = false;}}
子集——index方案
如果说上一题是完整的两种方法的运用,这一题就是只运用index技巧的题目
这一题的特点在于:不重复元素、用过的元素不能再用、在过程中间就得存储
/// 78. 子集pub fn subsets(mut nums: Vec<i32>) -> Vec<Vec<i32>> {fn dfs(index: usize, nums: &mut Vec<i32>, temp: &mut Vec<i32>, res: &mut Vec<Vec<i32>>) {// 因为要获取到每一个子阶段的数据,因此在这里pushres.push(temp.clone());if index == nums.len() {return;}for x in index..nums.len() {temp.push(nums[x]);dfs(x + 1, nums, temp, res);temp.pop();}}nums.sort();let mut res: Vec<Vec<i32>> = Vec::new();let mut temp = Vec::new();dfs(0, &mut nums, &mut temp, &mut res);res}
全排列——used方案
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
这一题的树与子集问题的比起来明显的差别就在于:
- 数是可以重复选择的,不是说,我考虑了存在1的情况就完事了,我需要考虑1放在什么位置的情况,即与顺序有关,与数无关
数列的重复当且仅当所有数一样时
/// 46. 全排列pub fn permute(mut nums: Vec<i32>) -> Vec<Vec<i32>> {let mut res: Vec<Vec<i32>> = Vec::new();fn dfs(nums: &mut Vec<i32>, temp: &mut Vec<i32>, res: &mut Vec<Vec<i32>>,used: &mut Vec<bool>, depth: usize) {if depth == nums.len() {res.push(temp.clone());return;}for x in 0..nums.len() {if used[x] {continue;}used[x] = true;temp.push(nums[x]);dfs(nums, temp, res, used, depth + 1);used[x] = false;temp.pop();}}let mut temp = Vec::new();let mut used = vec![false; nums.len()];dfs(&mut nums, &mut temp, &mut res, &mut used, 0);res}
全排列II——进阶的used
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
对于重复元素的处理方式,还是通过used,不同之处在于需要排序以及判断!used[x-1] && nums[x] == nums[x-1]
这也是子集II中的思路来源:
可以看看树:
明显的可以看出来,因为第二颗子树中需要再次用到1所以无法纵向剪枝,使用index
而我们需要剪枝重复使用过的数,具体来说是,重复在同一位置的数。
即与顺序有关,与数无关,可以使用多个一样的数
因此使用了used的进化版
/// 47. 全排列 IIpub fn permute_unique(mut nums: Vec<i32>) -> Vec<Vec<i32>> {nums.sort();let mut res: Vec<Vec<i32>> = Vec::new();fn dfs(nums: &mut Vec<i32>, temp: &mut Vec<i32>, res: &mut Vec<Vec<i32>>,used: &mut Vec<bool>, depth: usize) {if depth == nums.len() {res.push(temp.clone());return;}for x in 0..nums.len() {if used[x] {continue;}if x > 0 && !used[x-1] && nums[x] == nums[x-1] {continue;}used[x] = true;temp.push(nums[x]);dfs(nums, temp, res, used, depth + 1);used[x] = false;temp.pop();}}let mut temp = Vec::new();let mut used = vec![false; nums.len()];dfs(&mut nums, &mut temp, &mut res, &mut used, 0);res}
剑指 Offer 38. 字符串的排列——定长排列问题
这一题很像全排列II,使用进阶的used,但是不适用index
再次思考index究竟使用在什么地方,这一题的特征和组合问题比较起来就是在两种可能上:考虑[1,1,2]组合问题就是
[1,2,1]与[1,1,2]一样,因此在2的时候不能再用1,所以使用index排列问题就是
[1,2,1]与[1,1,2]不一样,因此使用used/// 剑指 Offer 38. 字符串的排列pub fn permutation(mut s: String) -> Vec<String> {let n = s.len();// 相比于使用四字节的chars的UTF8模式,u8能够节省一些空间,但是比较不方便let mut s: Vec<char> = s.chars().collect();s.sort();fn dfs(res: &mut Vec<String>, used: &mut Vec<bool>, depth: usize,temp: &mut String, s: &mut Vec<char>) {if depth >= s.len() {res.push(temp.clone());return;}for x in 0..s.len() {if used[x] {continue; }if x > 0 && s[x-1] == s[x] && !used[x-1] {continue;}used[x] = true;temp.push(s[x]);dfs(res, used, depth+1, temp, s);temp.pop();used[x] = false;}}let mut ans = Vec::new();let mut temp = String::new();let mut used = vec![false; s.len()];dfs(&mut ans, &mut used, 0, &mut temp, &mut s);ans}
