代码题(19)— 组合与排列

摘要:
示例:input:n=4,k=2输出:[[2,4],[3,4],[2,3],[1,2],[1,3],[1,3],[1,4],]classSolution{public:vector˂vector˃combine{vector˂vector˃res;vectortemp;combSum;return;}voidcombSum{if{res.push_back;return;}用于{temp.push_back;combSum;temp.pop_back();}};2.数组中n个元素的所有组合的想法如下:首先,我们发现这个字符组合必须包含A个字符的组合,然后必须确定A个字符,即包含S中第一个字符的字符串,然后使用剩余字符串BCDEF作为新字符串,以找出所有2个字符的合并,然后我们可以得到A。。

1、77. 组合

给定两个整数 n 和 k,返回 1 ... 中所有可能的 k 个数的组合。

示例:

输入: n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        vector<vector<int>> res;
        vector<int> temp;
        combSum(n, k, 1, temp, res);
        return res;
    }
    void combSum(int n, int k, int pos, vector<int> &temp, vector<vector<int>> &res)
    {
        if(temp.size() == k)
        {
            res.push_back(temp);
            return;
        }
        for(int i=pos;i<=n;++i)
        {
            temp.push_back(i);
            combSum(n,k,i+1,temp,res);
            temp.pop_back();
        }
    }
         
};

2、从数组中取出n个元素的所有组合

思路如下:

首先我们找到这个字符组合中一定包含A字符的组合,那么A字符肯定就定下来了,即包含S中第一个字符的组合,然后以剩下的字符串BCDEF作为新的字符串,找出所有的2个字符的组合,那就得到了A包含的所有组合了是吧。。

然后我们就可以省去A了,因为包含A的所有的组合都找到了,所以我们又开始以BCDEF这个字符串找出所有的3个字符的组合;

那么做法和上面一样,又以第一个为指定的字符,CDEF进行找出所有2个字符的组合。这样包含B开头的所有字符组合也找完了吧‘

依次遍历下去,达到E的时候,不能再进行了,因为剩余长度小于3个了。

  本质和上面是一样的/*我们有两种选择:第一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;
第二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符*/

void combineDfs(vector<int> &nums, int pos,int k, vector<int> &temp, vector<vector<int>> & res)
{
    if (temp.size() == k)
    {
        res.push_back(temp);
    }
    else
    {
        for (int i = pos; i < nums.size(); ++i) //选择放还是不放
        {
            temp.push_back(nums[i]);
            combineDfs(nums, i + 1, k, temp, res);
            temp.pop_back();
        }
    }
}

vector<vector<int>> combine(vector<int> &nums, int k)
{
    vector<int> temp;
    vector<vector<int>> res;
    combineDfs(nums, 0,k, temp, res);
    return res;

}

int main()
{
    int n = 5, k = 3;
    vector<int> nums;
    //int a[] = { 2,4,6,8 };
    for (int i = 1; i <= n; ++i)
    {
        nums.push_back(i);
    }
    vector<vector<int>> res;
    res = combine(nums, k);
    for (int i = 0; i < res.size(); ++i)
    {
        for (int j = 0; j < res[i].size(); ++j)
        {
            cout << res[i][j] << "  ";
        }
        cout << endl;
    }

    system("pause");
    return 0;
}

 3、46. 全排列

给定一个没有重复数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

(1)这道题是求全排列问题,给的输入数组没有重复项,这跟之前的组合和类似,解法基本相同,但是不同点在于那道不同的数字顺序只算一种,是一道典型的组合题,而此题是求全排列问题,还是用递归DFS来求解。这里我们需要用到一个visited数组来标记某个数字是否访问过,然后在DFS递归函数从的循环应从头开始,而不是从level开始,这是和组合不同的地方,其余思路大体相同。

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> temp;
        vector<int> visited(nums.size(),0);
        permuteDfs(nums,0,visited,temp,res);
        return res;
        
    }
    void permuteDfs(vector<int> &nums, int pos, vector<int> &visited, vector<int> &temp, vector<vector<int>> &res)
    {
        if(pos == nums.size())
            res.push_back(temp);
        else
        {
            for(int i=0;i<nums.size();++i)
            {
                if(visited[i] == 0)
                {
                    visited[i] = 1;
                    temp.push_back(nums[i]);
                    permuteDfs(nums,pos+1,visited,temp,res);
                    temp.pop_back();
                    visited[i] = 0;
                }
            }
        }
    }
};

 (2)还有一种递归的写法,更简单一些,这里是每次交换num里面的两个数字,经过递归可以生成所有的排列情况。

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> res;
        permuteDfs(nums, 0, res);
        return res;
        
    }
    void permuteDfs(vector<int> &nums, int pos, vector<vector<int>> &res)
    {
        if(pos == nums.size())
            res.push_back(nums);
        for(int i=pos;i<nums.size();++i)
        {
            swap(nums[pos], nums[i]);
            permuteDfs(nums, pos+1, res);
            swap(nums[pos], nums[i]);
        }
    }
    
};

4、47. 全排列 II

还是DFS,不过有重复,那重点就是去重了。 
同样深度的情况下,出现重复的,那么需要跳过。 具体说就是: 
判断是否和上一个相等,相等的情况下如果上一个没用过,说明是上一个回溯结束的,同一层,那么就不要再重新来一轮了,跳过。 112 分别以1,1,2开始,第二个1,和第一个1开始的结果重复的。 
在第一个1开始的时候,下一层的当前元素是第二个1,虽然也是1,但是上一个1被用了,说明它是不同深度的,所以不跳过。 
这道题是之前那道 Permutations 全排列的延伸,由于输入数组有可能出现重复数字,如果按照之前的算法运算,会有重复排列产生,我们要避免重复的产生,在递归函数中要判断前面一个数和当前的数是否相等,如果相等,前面的数必须已经使用了,即对应的visited中的值为1,当前的数字才能使用,否则需要跳过,这样就不会产生重复排列了 

class Solution {
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> temp;
        vector<int> visited(nums.size(), 0);
        sort(nums.begin(), nums.end());
        permute(nums, 0, visited, temp, res);
        return res;
         
    }
    void permute(vector<int> &nums, int pos, vector<int> &visited, vector<int> &temp, vector<vector<int>> &res)
    {
        if(temp.size() == nums.size())
        {
            res.push_back(temp);
        }
        else
        {
            for(int i=0;i<nums.size();++i)
            {
                if(visited[i] == 0)
                {
                    if(i>0 && nums[i] == nums[i-1] && visited[i-1] == 0)
                        continue;
                    visited[i] = 1;
                    temp.push_back(nums[i]);
                    permute(nums, i+1, visited, temp, res);
                    temp.pop_back();
                    visited[i] = 0;
                }
            }
        
        }
        
    }
};

还有一种比较简便的方法,在Permutations的基础上稍加修改,我们用set来保存结果,利用其不会有重复项的特点,然后我们再递归函数中的swap的地方,判断如果i和start不相同,但是nums[i]和nums[start]相同的情况下跳过,继续下一个循环.

class Solution {
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        set<vector<int>> res;
        permuteDfs(nums, 0, res);
        return vector<vector<int>> (res.begin(), res.end());
    }

    void permuteDfs(vector<int> &nums, int pos, set<vector<int>> &res)
    {
        if(pos == nums.size())
            res.insert(nums);
        for(int i=pos;i<nums.size();++i)
        {
            if (i != pos && nums[i] == nums[pos]) continue;
            swap(nums[pos], nums[i]);
            permuteDfs(nums, pos+1, res);
            swap(nums[pos], nums[i]);
        }
    }
};

免责声明:文章转载自《代码题(19)— 组合与排列》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇PHP分页完美参考MacOS install Maven下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Codeforces Round #685 (Div. 2) C. String Equality 思维

传送门 题意:给你一个原串和模式串,问你能否通过两种操作把原串变成模式串。 操作方法: 1.交换任意相邻字符。 2.将k长度的相同字符子串全+1。 思路: 对于操作1,相当于我们可以任意排序原串。 结合操作2,我们可以尽可能的先将原串中相同的字符聚集起来,然后看看模式串中对应字符的数量,如果原串中更多一点,我们就把多出来的全部丢给下一位字符(+1)。...

Unicode(UTF-8, UTF-16)令人混淆的概念

为啥需要Unicode       我们知道计算机其实挺笨的,它只认识0101这样的字符串,当然了我们看这样的01串时肯定会比较头晕的,所以很多时候为了描述简单都用十进制,十六进制,八进制表示.实际上都是等价的,没啥太多不一样.其他啥文字图片之类的其他东东计算机不认识.那为了在计算机上表示这些信息就必须转换成一些数字.你肯定不能想怎么转换就怎么转,必须得有...

SQL 给字符串补0

第一种方法: right('00000'+cast(@countasvarchar),5) 其中'00000'的个数为right函数的最后参数,例如这里是5,所以有5个0 @count就是被格式化的正整数 例如: 1、select right('00000'+cast(dense_rank() over( order by zsbh ) as VARCHA...

c# 正则表达式 匹配回车

1 "." 匹配除 " " 之外的任何单个字符,一般用".*?"匹配不包括回车的任意字符。 2 我们在用正则表达式分析html或者是xml的时候,会碰上要匹配的目标字符串含有回车换行的情况,这时候我们就不能试用 “.*?”匹配了(除非你先把字符串中的回车换行去掉)。我们应该用 "[\s\S]" 来代替 "."。 一般都会匹配形如:A任意字符B这样的模式,所...

VB 的字符串处理函数

一、InStr 返回 Variant (Long),指定一字符串在另一字符串中最先出现的位置。 语法 InStr([start, ]string1, string2[, compare]) start 可选参数。为数值表达式,设置每次搜索的起点。如果省略,将从第一个字符的位置开始。如果 start 包含 Null,将发生错误。如果指定了 compar...

_tcsrchr 规格严格

_tcsrchr #include <afx.h> 查找字符串中某个字符最后一次出现的位置 两个参数 第一个参数:字符串 第二个参数:查找的字符 返回值:指向最后一次在字符串中出现的该字符的指针,如果要查找的字符再串中没有出现,则返回NULL。 TCHAR szConfFile[MAX_PATH];::GetModuleFileName(...