C++ leetcode之排列与组合专题

简介: C++ leetcode之排列与组合专题

排列与组合


排列组合是组合学最基本的概念。所谓排列,就是指从给定个数的元素中取出指定个数的元素进行排序。组合则是指从给定个数的元素中仅仅取出指定个数的元素,不考虑排序。




1. 全排列


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


示例:

输入: [1,2,3]

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




方法一

#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
    vector<vector<int>> permute(vector<int> &nums)
    {
        vector<vector<int>> res;
        vector<bool> used(nums.size());
        dfs(nums, used, res);
        return res;
    }
private:
    vector<int> stack;
    void dfs(vector<int> &nums, vector<bool> &used, vector<vector<int>> &res)
    {
        if (stack.size() == nums.size())
        {
            res.push_back(stack);
        }
        else
        {
            for (int i = 0; i < nums.size(); i++)
            {
                if (!used[i])
                {
                    used[i] = true;
                    stack.push_back(nums[i]);
                    dfs(nums, used, res);
                    stack.pop_back();
                    used[i] = false;
                }
            }
        }
    }
};
int main()
{
  vector<int> nums = {1,2,3};
  Solution s;
  for (auto res : s.permute(nums)){
    for (auto item : res)
      cout << item << " ";
    cout << endl;
  }
  cout << endl;
  return 0;
} 



方法二

#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
    vector<vector<int>> result;
    vector<vector<int>> permute(vector<int> &nums)
    {
        vector<int> temp(nums.size());
        permutation(nums.size(), 0, nums, temp);
        return result;
    }
    void permutation(int n, int index, vector<int> &nums, vector<int> &temp)
    {
        if (index == n)
        {
            result.push_back(temp);
            return;
        }
        for (int i = 0; i < n; i++)
        {
            bool flag = true;
            for (int j = 0; j <= index - 1; j++)
            {
                if (temp[j] == nums[i])
                    flag = false;
            }
            if (flag)
            {
                temp[index] = nums[i];
                permutation(n, index + 1, nums, temp);
            }
        }
    }
};
int main()
{
  vector<int> nums = {1,2,3};
  Solution s;
  for (auto res : s.permute(nums)){
    for (auto item : res)
      cout << item << " ";
    cout << endl;
  }
  cout << endl;
  return 0;
} 



方法三

#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
    vector<vector<int>> permute(vector<int> &nums)
    {
        vector<vector<int>> res;
        BT(res, nums, 0);
        return res;
    }
    void BT(vector<vector<int>> &res, vector<int> &nums, int start)
    {
        if (start == nums.size())
        {
            res.push_back(nums);
            return;
        }
        else
        {
            for (int i = start; i < nums.size(); i++)
            {
                swap(nums[i], nums[start]);
                BT(res, nums, start + 1);
                swap(nums[i], nums[start]);
            }
        }
    }
};
int main()
{
  vector<int> nums = {1,2,3};
  Solution s;
  for (auto res : s.permute(nums)){
    for (auto item : res)
      cout << item << " ";
    cout << endl;
  }
  cout << endl;
  return 0;
} 



2. 全排列 II


给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。


示例 1:

输入:nums = [1,1,2]

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


示例 2:

输入:nums = [1,2,3]

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


提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

方法一

#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
    vector<vector<int>> permuteUnique(vector<int> &nums)
    {
        vector<vector<int>> res;
        int n = nums.size();
        vector<int> temp;
        vector<bool> visited(n, false);
        sort(nums.begin(), nums.end());
        backtrackpermuteUnique(0, n, nums, temp, res, visited);
        return res;
    }
    void backtrackpermuteUnique(int k, int n, vector<int> nums, vector<int> &temp, vector<vector<int>> &res, vector<bool> &visited)
    {
        if (k == n)
        {
            res.push_back(temp);
            return;
        }
        for (int i = 0; i < n; i++)
        {
            if (!visited[i])
            {
                if (i > 0 && nums[i] == nums[i - 1] && visited[i - 1])
                    continue;
                temp.push_back(nums[i]);
                visited[i] = true;
                backtrackpermuteUnique(k + 1, n, nums, temp, res, visited);
                temp.pop_back();
                visited[i] = false;
            }
        }
    }
};
int main()
{
  vector<int> nums = {1,1,2};
  Solution s;
  for (auto res : s.permuteUnique(nums)){
    for (auto item : res)
      cout << item << " ";
    cout << endl;
  }
  cout << endl;
  return 0;
} 



方法二

#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
    vector<vector<int>> permuteUnique(vector<int> &nums)
    {
        vector<vector<int>> res;
        vector<bool> used(nums.size());
        sort(nums.begin(), nums.end());
        dfs(nums, used, res);
        return res;
    }
private:
    vector<int> stack;
    void dfs(vector<int> &nums, vector<bool> &used, vector<vector<int>> &res)
    {
        if (stack.size() == nums.size())
        {
            res.push_back(stack);
        }
        else
        {
            for (int i = 0; i < nums.size(); i++)
            {
                if (!used[i])
                {
                    if (i > 0 && !used[i - 1] && nums[i - 1] == nums[i])
                    {
                        continue;
                    }
                    stack.push_back(nums[i]);
                    used[i] = true;
                    dfs(nums, used, res);
                    stack.pop_back();
                    used[i] = false;
                }
            }
        }
    }
};
int main()
{
  vector<int> nums = {1,1,2};
  Solution s;
  for (auto res : s.permuteUnique(nums)){
    for (auto item : res)
      cout << item << " ";
    cout << endl;
  }
  cout << endl;
  return 0;
} 




3. 组合总和


给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。


candidates 中的数字可以无限制重复被选取。


说明:

  • 所有数字(包括 target)都是正整数。
  • 解集不能包含重复的组合。

示例 1:

输入:candidates = [2,3,6,7], target = 7,

输出:[[7],[2,2,3]]



示例 2:

输入:candidates = [2,3,5], target = 8,

输出:[[2,2,2,2],[2,3,3],[3,5]]

提示:

   1 <= candidates.length <= 30

   1 <= candidates[i] <= 200

   candidate 中的每个元素都是独一无二的。

   1 <= target <= 500



方法一  

#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
    void compute(int start, int target, vector<int> &tmp, vector<int> &candidates, vector<vector<int>> &ans)
    {
        int n = candidates.size();
        for (int i = start; i < n; i++)
        {
            if (target > 0)
            {
                tmp.push_back(candidates[i]);
                compute(i, target - candidates[i], tmp, candidates, ans);
                tmp.pop_back();
            }
            else if (target < 0)
                return;
            else
            {
                ans.push_back(tmp);
                return;
            }
        }
    }
    vector<vector<int>> combinationSum(vector<int> &candidates, int target)
    {
        vector<vector<int>> ans;
        vector<int> tmp;
        int v;
        sort(candidates.begin(), candidates.end());
        compute(0, target, tmp, candidates, ans);
        return ans;
    }
};
int main()
{
  vector<int> result, candidates = {2,3,6,7};
  int target = 7;
  Solution s;
  for (auto candidate : s.combinationSum(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  cout <<endl;
  candidates = {2,3,5};
  target = 8;
  for (auto candidate : s.combinationSum(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  return 0;
} 



方法二

#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
    vector<vector<int>> combinationSum(vector<int> &candidates, int target)
    {
        vector<vector<int>> res;
        dfs(candidates, 0, target, res);
        return res;
    }
private:
    vector<int> stack;
    void dfs(vector<int> &candidates, int start, int target, vector<vector<int>> &res)
    {
        if (target < 0)
        {
            return;
        }
        else if (target == 0)
        {
            res.push_back(stack);
        }
        else
        {
            for (int i = start; i < candidates.size(); i++)
            {
                stack.push_back(candidates[i]);
                dfs(candidates, i, target - candidates[i], res);
                stack.pop_back();
            }
        }
    }
};
int main()
{
  vector<int> result, candidates = {2,3,6,7};
  int target = 7;
  Solution s;
  for (auto candidate : s.combinationSum(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  cout <<endl;
  candidates = {2,3,5};
  target = 8;
  for (auto candidate : s.combinationSum(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  return 0;
} 



方法三

#include <bits/stdc++.h>
using namespace std;
class Solution
{
private:
    vector<vector<int>> res;
    vector<int> ans;
public:
    vector<vector<int>> combinationSum(vector<int> &candidates, int target)
    {
        sort(candidates.begin(), candidates.end());
        int left = 0, right = 0;
        for (; right < candidates.size() && candidates[right] <= target; right++)
            ;
        backtrack(candidates, left, right == candidates.size() ? right - 1 : right, target);
        return res;
    }
private:
    void backtrack(vector<int> &candidates, int left, int right, int target)
    {
        if (target < 0)
            return;
        if (!target)
        {
            res.push_back(ans);
            return;
        }
        for (int i = left; i <= right && candidates[i] <= target; i++)
        {
            ans.push_back(candidates[i]);
            backtrack(candidates, i, right, target - candidates[i]);
            ans.pop_back();
        }
    }
};
int main()
{
  vector<int> result, candidates = {2,3,6,7};
  int target = 7;
  Solution s;
  for (auto candidate : s.combinationSum(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  cout <<endl;
  candidates = {2,3,5};
  target = 8;
  Solution s2;
  for (auto candidate : s2.combinationSum(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  return 0;
} 




4. 组合总和 II


给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。


candidates 中的每个数字在每个组合中只能使用一次。


说明:


   所有数字(包括目标数)都是正整数。

   解集不能包含重复的组合。  



示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,

所求解集为:[[1, 7],[1, 2, 5],[2, 6],[1, 1, 6]]


示例 2:

输入: candidates = [2,5,2,1,2], target = 5,

所求解集为:[[1,2,2],[5]]



方法一

#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
    vector<vector<int>> combinationSum2(vector<int> &candidates, int target)
    {
        vector<vector<int>> res;
        sort(candidates.begin(), candidates.end());
        dfs(candidates, 0, target, res);
        return res;
    }
private:
    vector<int> stack;
    void dfs(vector<int> &candidates, int start, int target, vector<vector<int>> &res)
    {
        if (target < 0)
        {
            return;
        }
        else if (target == 0)
        {
            res.push_back(stack);
        }
        else
        {
            int last = INT_MIN;
            for (int i = start; i < candidates.size(); i++)
            {
                if (last != candidates[i])
                {
                    stack.push_back(candidates[i]);
                    dfs(candidates, i + 1, target - candidates[i], res);
                    stack.pop_back();
                }
                last = candidates[i];
            }
        }
    }
};
int main()
{
  vector<int> candidates = {10,1,2,7,6,1,5};
  int target = 8;
  Solution s;
  for (auto candidate : s.combinationSum2(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  cout <<endl;
  candidates = {2,5,2,1,2};
  target = 5;
  for (auto candidate : s.combinationSum2(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  return 0;
} 


方法二

#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
    void dfs(vector<vector<int>> &ans, vector<int> &candidates, vector<int> &tmp, int target, int start)
    {
        if (target == 0)
        {
            ans.push_back(tmp);
            return;
        }
        else if (target < 0)
        {
            return;
        }
        else
        {
            for (int i = start; i < candidates.size(); i++)
            {
                tmp.push_back(candidates[i]);
                dfs(ans, candidates, tmp, target - candidates[i], i + 1);
                tmp.pop_back();
                while (i + 1 < candidates.size() && candidates[i] == candidates[i + 1])
                    i++;
            }
        }
    }
    vector<vector<int>> combinationSum2(vector<int> &candidates, int target)
    {
        vector<vector<int>> ans;
        vector<int> tmp;
        if (candidates.empty())
            return ans;
        sort(candidates.begin(), candidates.end());
        dfs(ans, candidates, tmp, target, 0);
        return ans;
    }
};
int main()
{
  vector<int> candidates = {10,1,2,7,6,1,5};
  int target = 8;
  Solution s;
  for (auto candidate : s.combinationSum2(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  cout <<endl;
  candidates = {2,5,2,1,2};
  target = 5;
  for (auto candidate : s.combinationSum2(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  return 0;
} 



方法三

#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
    vector<vector<int>> combinationSum2(vector<int> &candidates, int target)
    {
        vector<vector<int>> res;
        vector<int> temp;
        backtrace(candidates, temp, 0, target);
        res.assign(m_set.begin(), m_set.end());
        return res;
    }
    void backtrace(vector<int> &candidates,
                   vector<int> &temp,
                   int index,
                   int target)
    {
        if (target == 0)
        {
            sort(temp.begin(), temp.end());
            /* 去重 */
            m_set.insert(temp);
            return;
        }
        /* 设定边界*/
        if (index == candidates.size())
        {
            return;
        }
        if (target >= candidates[index])
        {
            vector<int> tmp(temp);
            tmp.push_back(candidates[index]);
            backtrace(candidates, tmp, index + 1, target - candidates[index]);
        }
        backtrace(candidates, temp, index + 1, target);
    }
private:
    set<vector<int>> m_set;
};
int main()
{
  vector<int> candidates = {10,1,2,7,6,1,5};
  int target = 8;
  Solution s;
  for (auto candidate : s.combinationSum2(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  cout <<endl;
  candidates = {2,5,2,1,2};
  target = 5;
  Solution s2;
  for (auto candidate : s2.combinationSum2(candidates, target)){
    for (auto item : candidate)
      cout << item << " ";
    cout << endl;
  }
  return 0;
} 




目录
相关文章
|
2月前
|
算法 C++ 容器
Leetcode第三十一题(下一个排列)
这篇文章介绍了LeetCode第31题“下一个排列”的C++解决方案,该算法通过原地修改数组来找到下一个字典序更大的排列,如果不存在则重排为字典序最小的排列。
31 0
Leetcode第三十一题(下一个排列)
|
6月前
|
存储 算法 数据挖掘
python 数学+减治、下一个排列法、DFS回溯法实现:第 k 个排列【LeetCode 题目 60】
python 数学+减治、下一个排列法、DFS回溯法实现:第 k 个排列【LeetCode 题目 60】
|
7月前
|
算法 C语言 容器
从C语言到C++_18(stack和queue的常用函数+相关练习)力扣(上)
从C语言到C++_18(stack和queue的常用函数+相关练习)力扣
49 0
|
4月前
|
算法 Java
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
55 0
|
6月前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-2
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
6月前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-1
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
7月前
|
算法 C语言 容器
从C语言到C++_25(树的十道OJ题)力扣:606+102+107+236+426+105+106+144+94+145(下)
从C语言到C++_25(树的十道OJ题)力扣:606+102+107+236+426+105+106+144+94+145
66 7
|
7月前
|
存储 算法 C语言
从C语言到C++_39(C++笔试面试题)next_permutation刷力扣
从C语言到C++_39(C++笔试面试题)next_permutation刷力扣
62 5
|
7月前
|
存储 C语言 容器
从C语言到C++_26(set+map+multiset+multimap)力扣692+349+牛客_单词识别(下)
从C语言到C++_26(set+map+multiset+multimap)力扣692+349+牛客_单词识别
47 1
|
7月前
|
存储 C语言 容器
从C语言到C++_26(set+map+multiset+multimap)力扣692+349+牛客_单词识别(中)
从C语言到C++_26(set+map+multiset+multimap)力扣692+349+牛客_单词识别
48 1