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. 初始化空集:[[]]
  2. 把第一个数加在之前初始化的集合中:[[],[1]]
  3. 把第二个数加在之前的集合中:[[], [1], [3], [1, 3]]
  4. 把第三个数加在之前的集合中:[[], [1], [3], [1,3],[5], [1, 5], [3, 5], [1,3,5]]

2. 组合

  • 最好是先sort原有数组
  • 初始化一个二维数组用来保存结果
  • 取原有数组里的值,一个一个的来处理
  • 循环结果数组的数,结合原有数组的值组合
  • 若原有数组有重复的值,需要检查重复性;将组合好的数组在之前的结果数组里寻找,若没找到则加到结果数组中;若找到了则忽略。

3. 排列(递归处理)

  • 初始化两个指针交换元素,j指向原有数组值,index指向 j 并在递归中依次加1
  • index指针向后移并递归交换
  • 再次交换元素为了变成原来的数组
  • 直到index指向数组的最后一个数,则将排列后的数组存入结果数组中

 参考资料:

  1. https://leetcode.com/problems/subsets/
  2. https://leetcode.com/problems/subsets-ii/
  3. https://leetcode.com/problems/permutations/
  4. https://leetcode.com/problems/letter-case-permutation/
  5. https://leetcode.com/problems/generate-parentheses/
posted @ 2020-09-11 21:36  cancantrbl  阅读(318)  评论(0编辑  收藏  举报