zoukankan      html  css  js  c++  java
  • 面试:全排列组合实现

    一、全排列

    递归暴力DFS:

      面试中,排列组合的实现是需要掌握的。一般最先想到的方法是暴力循环法,即对于每一位,遍历集合中可能的元素,如果在这一位之前出现过了该元素,跳过该元素。例如对于abc,第一位可以是 a 或 b 或 c 。当第一位为 a 时,第二位再遍历集合,发现 a 不行,因为前面已经出现 a 了,而 b 和 c 可以。当第二位为 b 时 , 再遍历集合,发现 a 和 b 都不行,c 可以。可以用递归或循环来实现,但是复杂度为 O(nn) 。

     1 void permutation1(string src, string path, vector<string>& res) {
     2     if (path.size() == src.size()) {
     3         res.push_back(path);
     4         return;
     5     }
     6     int len = src.length();
     7     for (int i = 0; i < len; i++) {
     8         if (path.find(src[i]) == string::npos) {
     9             path.push_back(src[i]);
    10             permutation1(src, path, res);
    11             path.pop_back();
    12         }
    13     }
    14 }
    15 
    16 vector<string> permutation(string src) {
    17     vector<string> res;
    18     permutation1(src, "", res);
    19     return res;
    20 }

    交换:

    首先考虑baccba这二个字符串是如何得出的。显然这二个都是abc中的 a 与后面两字符交换得到的。然后可以将abc的第二个字符和第三个字符交换得到acb。同理可以根据baccba来得bcacab。因此可以知道 全排列就是从第一个数字起每个数分别与它后面的数字交换,也可以得出这种解法每次得到的结果都是正确结果,所以复杂度为 O(n!)。

     1 void permutation2(string src, int start, vector<string>& res) {
     2     int n = src.size();
     3     if (start == n - 1) {
     4         res.push_back(src);
     5         return;
     6     }
     7 
     8     for (int i = start; i < n; i++) {
     9         std::swap(src[start], src[i]);
    10         permutation2(src, start + 1, res);
    11         std::swap(src[start], src[i]);
    12     }
    13 }

    去重的全排列

    有时候给出的src中出现重复的字符,类如abb。按照上面的排列方法得出的结果里面会有重复的字符串。为了得到不一样的排列,去重的全排列要从第一个数字起每个数分别与它后面非重复出现的数字交换。用编程的话描述就是第i个数与第j个数交换时,要求[i,j)中没有与第j个数相等的数

     1 void permutation3(string src, int start, vector<string>& res) {
     2     int n = src.size();
     3     if (start == n - 1) {
     4         res.push_back(src);
     5         return;
     6     }
     7 
     8     for (int i = start; i < n; i++) {
     9         bool isRepeated = false;
    10         for (int j = start; j < i; j++) {
    11             if (src[j] == src[i]) {
    12                 isRepeated = true;
    13                 break;
    14             }
    15         }
    16         if (!isRepeated) {
    17             std::swap(src[start], src[i]);
    18             permutation2(src, start + 1, res);
    19             std::swap(src[start], src[i]);
    20         }
    21     }
    22 }

    二、组合

    DFS暴力枚举:

     1 void combination2(string src, int start, string path, vector<string>& res) {
     2     int len = src.length();
     3     if (start == len) {
     4         if (!path.empty()) {
     5             res.push_back(path);
     6         }
     7         return;
     8     }
     9     combination2(src, start + 1, path, res);
    10     path.push_back(src[start]);
    11     combination2(src, start + 1, path, res);
    12 }
    13 
    14 vector<string> combination2(string src) {
    15     if (src.empty())
    16         return {};
    17     vector<string> res;
    18     combination2(src, 0, "", res);
    19     return res;
    20 }

    二进制法:

     1 //二进制法
     2 vector<string> combination(string src) {
     3     if (src.empty())
     4         return {};
     5     int len = src.length();
     6     int n = 1 << len;
     7     vector<string> res;
     8     for (int i = 0; i < n; i++) {
     9         string tmp;
    10         for (int j = 0; j < len; j++) {
    11             if (i & (1 << j)) {
    12                 tmp.push_back(src[j]);
    13             }
    14         }
    15         if (!tmp.empty()) {
    16             res.push_back(tmp);
    17         }
    18     }
    19     return res;
    20 }
  • 相关阅读:
    函数对象中的prototype属性
    undefined和null的区别
    访问修饰符
    继承
    静态成员和实例成员的区别
    js模拟Trim()方法
    连接池的执行原理
    Javascript中的= =(等于)与= = =(全等于)区别
    数据库中创建约束
    KM算法入门
  • 原文地址:https://www.cnblogs.com/wxquare/p/4719228.html
Copyright © 2011-2022 走看看