Leetcode刷题 - 排列组合类
78. 子集 - Subsets
题目:https://leetcode.com/problems/subsets/
class Solution { public: vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> output; output.push_back({}); for (int i = 0; i < nums.size(); i++){ int size = output.size(); for (int j = 0; j < size; j++){ auto sub = output[j]; sub.push_back(nums[i]); output.push_back(sub); } } return output; } };
90. 子集 - Subsets II
题目:https://leetcode.com/problems/subsets-ii/
class Solution { public: vector<vector<int>> subsetsWithDup(vector<int>& nums) { sort(nums.begin(), nums.end()); vector<vector<int>> output; output.push_back({}); for (int i = 0; i < nums.size(); i++){ int size = output.size(); for (int j = 0; j < size; j++){ auto temp = output[j]; temp.push_back(nums[i]); // handle duplicate cases bool found = false; // find whether there is a duplicate case for (int k = 0; k < output.size(); k ++){ if (temp == output[k]){ found = true; break; } } if(!found) output.push_back(temp); } } return output; } };
46. 排列 - Permutation
题目:https://leetcode.com/problems/permutations/
class Solution { public: vector<vector<int>> permute(vector<int>& nums) { vector<vector<int>> result; helper(nums, 0, result); return result; } void helper (vector<int>& nums, int index, vector<vector<int>>& ans){ // 如果 i 移到数组的最后,则加入排过的数组并加入结果数组中 if (index == nums.size()){ ans.push_back(nums); return; } // 两个指针,index作为递归处理, j作为迭代处理 for (int j = index; j < nums.size(); j ++){ //内部交换 swap(nums[index], nums[j]); //递归处理 helper(nums, index+1, ans); //变回原来的数组 swap(nums[index], nums[j]); } } };
剑指OFFER:字符串排列组合
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
题目:https://www.nowcoder.com/practice/fe6b651b66ae47d7acce78ffdd9a96c7?tpId=13&&tqId=11180&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
class Solution { public: vector<string> Permutation(string str) { vector<string> result; if(str.size() == 0) return result; helper(str, 0, result); // 整理排序顺序 sort(result.begin(), result.end()); return result; } void helper(string str, int index, vector<string> & ans){ //若组合到最后一个,则弹出 if (index == str.size()){ ans.push_back(str); return; } for (int j = index; j < str.size(); j++){ // 处理重复元素 if(j!=index && str[j] == str[index]) continue; // 交换 swap(str[index], str[j]); helper(str, index+1, ans); // 交换回来 swap(str[index], str[j]); } } };
784. 字母大小写排列 - Letter Case Permutation
class Solution { public: vector<string> letterCasePermutation(string S) { vector<string> res({S}); // 将S加入结果数组中 // 取原有数组的值 for(int i = 0; i < S.size(); i ++){ if (isdigit(S[i])) continue; int size = res.size(); // 迭代结果数组 for (int j = 0; j < size; j++){ string temp = res[j]; temp[i] ^= 32; //利用XOR with 32 changes改变大小写 /***** * 详解XOR * 大小写字母的二进制ASCII码只有第6位有所不同 * 利用异或位运算(XOR)来实现相互转换。 * 32 or(1 << 5) * 或者 temp[i] ^= ' '; 因为空格的ASCII为32 ******/ res.push_back(temp); } } return res; } };
22. 括号生成排列 - Generate Parentheses
class Solution { public: vector<string> ans; vector<string> generateParenthesis(int n) { //利用递归方法 helper("", n, n); return ans; } void helper(string s, int open, int close){ if (open == 0 && close == 0){ ans.push_back(s); return; } if (open > 0) helper(s+"(", open - 1, close); // “(” 必须在 “)”之前,所以没加 “)”之前,"(" 要比 “)”多 if(open < close) helper(s+")", open, close - 1); } };
总结
1. 子集模式的举例:[1, 3, 5]
- 初始化空集:[[]]
- 把第一个数加在之前初始化的集合中:[[],[1]]
- 把第二个数加在之前的集合中:[[], [1], [3], [1, 3]]
- 把第三个数加在之前的集合中:[[], [1], [3], [1,3],[5], [1, 5], [3, 5], [1,3,5]]
2. 组合
- 最好是先sort原有数组
- 初始化一个二维数组用来保存结果
- 取原有数组里的值,一个一个的来处理
- 循环结果数组的数,结合原有数组的值组合
- 若原有数组有重复的值,需要检查重复性;将组合好的数组在之前的结果数组里寻找,若没找到则加到结果数组中;若找到了则忽略。
3. 排列(递归处理)
- 初始化两个指针交换元素,j指向原有数组值,index指向 j 并在递归中依次加1
- index指针向后移并递归交换
- 再次交换元素为了变成原来的数组
- 直到index指向数组的最后一个数,则将排列后的数组存入结果数组中
参考资料:
- https://leetcode.com/problems/subsets/
- https://leetcode.com/problems/subsets-ii/
- https://leetcode.com/problems/permutations/
- https://leetcode.com/problems/letter-case-permutation/
- https://leetcode.com/problems/generate-parentheses/