目录

一.子集

二.子集II

三.全排列

四.全排列II

五.字符全排列

六.字符串大小全排列

七.组合总和

八.组合总和II

九.组合总和III

十.组合总和IV

十一.递增子序列


一.子集

剑指 Offer II 079. 所有子集 - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

解题思路:

1.暴力枚举即可,就是每个元素有两种选择,一个是要,一个是不要。我们将其全部枚举出来即可:以数组[1,2,3]为例:

总结一下就是:

①画出递归树,找到状态变量(回溯函数的参数),这一步非常重要※
②根据题意,确立结束条件
③找准选择列表(与函数参数相关),与第一步紧密关联※
④判断是否需要剪枝
⑤作出选择,递归调用,进入下一层
⑥撤销选择

对应过程图:

对应代码:

class Solution {
public:vector<vector<int>>ans;//记录答案vector<vector<int>> subsets(vector<int>& nums) {vector<int>tmp;process(nums,0,tmp);return ans;}void process(vector<int>&nums,int index,vector<int>&tmp){if(nums.size()==index){ans.push_back(tmp);return;}//不选择当前的数process(nums,index+1,tmp);tmp.push_back(nums[index]);//选择当前的数process(nums,index+1,tmp);tmp.pop_back();//递归回来的时侯删掉}
};

二.子集II

90. 子集 II - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

解题思路:

本题与上题不同的是数组中有重复的元素,这样我们在一个数选或者一个数不选的时候就有可能出现重复的子集,而题目要求我们不能出现重复的子集,所以在这里我们需要剪枝,这里以数组[1,2,2,3]为例

 这里出现了重复的子集,那么怎么过滤掉重复的呢,就是在同一深度的两个不同的分支,如果当前元素和前面的元素相同,我们就跳过。如下图所示。

对应代码:

class Solution {
public:vector<int>tmp;vector<vector<int>>ans;vector<vector<int>> subsetsWithDup(vector<int>& nums) {sort(nums.begin(),nums.end());//注意一定要排序//方便去重process(nums,0,INT_MAX);return ans;}void process(vector<int>&nums,int index,int prev)//prev代表前一个已经被选择的元素{if(index==nums.size())//如果已经到了最后了{ans.push_back(tmp);return;}tmp.push_back(nums[index]);//选择当前的数process(nums,index+1,nums[index]);tmp.pop_back();//撤回选择if(nums[index]!=prev)//如果当前数和前一个选择的数不相等才进行下一个分支process(nums,index+1,prev);}
};

三.全排列

46. 全排列 - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

解题思路:

每个元素在自己可以尝试的位置,每一个位置都尝试一下。每个元素只能尝试自己和自己后面的位置。下面展示数组[1,2,3]的全排列

对应代码:

class Solution {
public:vector<vector<int>>ans;vector<vector<int>> permute(vector<int>& nums) {process(nums,0);return ans;}void process(vector<int>&nums,int i){if(i==nums.size())//不能交互{ans.push_back(nums);return;}for(int j=i;j<nums.size();j++){swap(nums[i],nums[j]);//来到当前位置process(nums,i+1);swap(nums[i],nums[j]);//撤销决定}}};

四.全排列II

对应letecode链接:

47. 全排列 II - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

解题思路:

本题与上题唯一不同的是数组中有重复的元素,因此如果我们不做任何去重处理的话肯定会出现重复的全排列。因此我们需要进行去重,如何去重了?我们只需要定义一张哈希表记录当前已经来到了的位置,如果来到的下一个位置和已经在哈希表里面记录过了则跳过。

具体请看代码:

class Solution {
public:vector<vector<int>>ans;//记录答案vector<vector<int>> permuteUnique(vector<int>& nums) {sort(nums.begin(),nums.end());//排序更容易去重不排序也行process(nums,0);return ans;}void process(vector<int>&nums,int i){if(i==nums.size()){ans.push_back(nums);}unordered_set<int>Hash;//记录访问过了的位置for(int j=i;j<nums.size();j++){if(!Hash.count(nums[j]))//查看上次来到的位置和这次来到位置是否相同{Hash.insert(nums[j]);swap(nums[i],nums[j]);process(nums,i+1);//去下一个位置swap(nums[i],nums[j]);//撤销决定}}}};

五.字符全排列

剑指 Offer 38. 字符串的排列 - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

解题思路:

本题和上题没有什么区别就只是一个是数字一个是字符而已。思路上题已经讲过在这里就只给出代码。

对应代码:

class Solution {
public:vector<string>ans;vector<string> permutation(string s) {process(s,0);return ans;}void process( string&str,int i){if(i==str.size()){ans.push_back(str);}vector<bool>isVisit(256,false);for(int j=i;j<str.size();j++){if(!isVisit[str[j]-'a']){isVisit[str[j]-'a']=true;swap(str[i],str[j]);process(str,i+1);swap(str[i],str[j]);}}}
};

六.字符串大小全排列

784. 字母大小写全排列 - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

解题思路:

每一个位置如果是字母就有两种选择:1.不变,2变成大小或者小写。如果不是字符就不变直接到下一个位置去。

七.组合总和

39. 组合总和 - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

解题思路:

同样的本题两个元素有选和不选两种选择,只不过本题每个元素可以选择无数次,按照之前的方法即可:

①画出递归树,找到状态变量(回溯函数的参数),这一步非常重要※
②根据题意,确立结束条件
③找准选择列表(与函数参数相关),与第一步紧密关联※
④判断是否需要剪枝
⑤作出选择,递归调用,进入下一层
⑥撤销选择

本题可以先对数组排序方便递归过程中的剪枝,具体请看代码:

对应代码:

class Solution {
public:vector<vector<int>>ans;//记录答案vector<int>tmp;vector<vector<int>> combinationSum(vector<int>& candidates, int target) {sort(candidates.begin(),candidates.end());//排序方便后序剪枝优化dfs(candidates,target,0);return ans;}void dfs(vector<int>&nums,int target,int index){if(target==0)//是否已经找到答案了{ans.push_back(tmp);return;}for(int i=index;i<nums.size();i++){if(nums[i]>target)//如果当前数大于target由于数组有序所以后面的数都是大于target//不可能在凑出target{return;}tmp.push_back(nums[i]);//选择当前的数dfs(nums,target-nums[i],i);//注意不是i+1而是i因为一个数可以选择多次tmp.pop_back();//撤销决定}}
};

八.组合总和II

40. 组合总和 II - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

解题思路:

本题和上题基本上没有什么变化,只不过多了一步去重的操作:

对应代码:

class Solution {
public:vector<vector<int>>ans;vector<int>tmp;vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {sort(candidates.begin(),candidates.end());process(candidates,target,0);return ans;}void process(vector<int>&nums,int target,int index){if(target==0){ans.push_back(tmp);return; }for(int i=index;i<nums.size();i++){if(i>index&&nums[i]==nums[i-1])//防止出现重复元素{continue;}if(nums[i]>target)//有序数组后面不可能搞出target了{return;}tmp.push_back(nums[i]);//选择当前的数process(nums,target-nums[i],i+1);tmp.pop_back();//撤销选择}}
};

九.组合总和III

216. 组合总和 III - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

解题思路:

本题解题思路和上题基本一样而且还不要去重,是上题的弱化版本,具体请看代码。

对应代码:

class Solution {
public:vector<int>tmp;vector<vector<int>>ans;vector<vector<int>> combinationSum3(int k, int n) {process(k,1,n);return ans;}void process(int k,int index,int taraget){if(k==0&&taraget==0)//说明已经找到了{ans.push_back(tmp);return;}for(int i=index;i<=9;i++)//从index到9;{tmp.push_back(i);//选择当前的数process(k-1,i+1,taraget-i);tmp.pop_back();//撤回选择}}
};

十.组合总和IV

377. 组合总和 Ⅳ - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

解题思路:

本题的解题思路依然是暴力递归和前面题目不同的是,只不过每次都可以从0号位置开始。具体请看代码:

对应代码:

int combinationSum4(vector<int>& nums, int target) {return process(nums,target);}int process(vector<int>&nums,int target){if(target<0)//如果target小于0那么没有方法数{return 0;}if(target==0)//到0了{return 1;}int ans=0;for(int i=0;i<nums.size();i++){ans+=process(nums,target-nums[i]);//选择当前的数}return ans;//返回答案即可}

但是非常的遗憾由于有大量重复的计算让这种方法直接超时了:

解决这个问题的方法有两种一种是记忆化搜索,一种是动态规划。下面这两种方法都一一给出:

记忆化搜索:其实特别的简单,我么可以定义一个dp表在返回之前把答案提前记录一下,如果发现答案已经被记录过了我可以直接返回不需要再调用递归重复的计算:

class Solution {
public:vector<int>dp;int combinationSum4(vector<int>& nums, int target) {dp.resize(target+1);return Dp(nums,target);}int process(vector<int>&nums,int target){if(target==0){return 1;}if(target<0){return 0;}if(dp[target]!=-1)//说明之前已经计算过了{return dp[target];}int ans=0;for(int i=0;i<nums.size();i++){ans+=process(nums,target-nums[i]);}dp[target]=ans;//提前将答案记录一下return ans;//返回答案}

动态规划版本就是再递归的基础上该过来而已:

class Solution {
public:vector<int>dp;int combinationSum4(vector<int>& nums, int target) {dp.resize(target+1);return Dp(nums,target);}int process(vector<int>&nums,int target){if(target==0){return 1;}if(target<0){return 0;}if(dp[target]!=-1)//说明之前已经计算过了{return dp[target];}int ans=0;for(int i=0;i<nums.size();i++){ans+=process(nums,target-nums[i]);}dp[target]=ans;//提前将答案记录一下return ans;//返回答案}int Dp(vector<int>&nums,int target){vector<int>dp(target+1);dp[0]=1;//根据递归函数的base填的for(int i=1;i<=target;i++){long long  ans=0;for(int j=0;j<nums.size();j++)//这一部分直接抄递归函数{if(i-nums[j]>=0)//组合数小于0{ans+=dp[i-nums[j]];} }dp[i]=ans;}return dp[target];//根据递归函数的调用确定返回值}};

十一.递增子序列

491. 递增子序列 - 力扣(LeetCode) (leetcode-cn.com)

题目描述:

解题思路:

同样的是一个元素选和不选的两种选择但是本题要求的是要是递增所以我们再定义递归函数时需要添加一个参数表示数组中的前一个元素,来判断这个数能不能被选以及在不选这个数时进行去重.以[6,7,7,7]为例

对应代码:

class Solution {
public:vector<int>tmp;vector<vector<int>>ans;vector<vector<int>> findSubsequences(vector<int>& nums) {dfs(nums,0,INT_MIN);return ans;}void dfs(vector<int>&nums,int index,int pre){if(index==nums.size())//达到了答案{if(tmp.size()>=2)//判断是否满足至少有两个数{ans.push_back(tmp);}return;}if(nums[index]>=pre)//判断是否满足条件{tmp.push_back(nums[index]);dfs(nums,index+1,nums[index]);tmp.pop_back();}if(nums[index]!=pre)//出重{dfs(nums,index+1,pre);}}
};

子集全排列组合数问题(带你轻松拿捏十一道OJ题)相关推荐

  1. Apifox:详细使用教程,带你轻松拿捏

    目录 Apifox简介 Apifox的安装与使用 Apifox新建项目的流程 编写接口文档 Apifox简介 我们在日常编程开发过程中经常实行的是前后端分离架构的模式,一个项目的落地会通过产品.开发. ...

  2. LeetCode刷题——链表OJ(历时三天,万字博客,十一道经典题,带你手撕链表)

    知之愈明,则行之愈笃:行之愈笃,则知之益明. 学完链表,我们不得刷刷题增进对链表的认识?今天博主选取十一道经典链表题,从刷题者的角度剖析重点和易错点,讲解最简单的方法,文章内附题目和题目链接,重点内容 ...

  3. Make!Sense 动手好伴侣,带你轻松做实验

     Make!Sense 动手好伴侣,带你轻松做实验 你是否对大自然各种神奇的现象充满了好奇心,但面对错综复杂的实验却无从下手?无论是实验步骤还是所需材料,对普通人来说都太难 get.而 Make! ...

  4. 从原理到实践,手把手带你轻松get数仓双集群容灾

    摘要:本文通过介绍双集群的架构.log结构.分析步骤来介绍双集群容灾的问题分析方法. 本文分享自华为云社区<从原理到实践,手把手带你轻松get数仓双集群容灾>,原文作者:Puyol . 双 ...

  5. 美妆海报不会做? PSD分层模板带你轻松掌握!

    美妆海报最重视视觉的感觉,海报的设计尤为重要! 这个时候没有灵感了怎么办? 不要急文案之后,先理清文案信息,用亲密性原则解决信息之间的关系,再了解其所在行业的 项目调性,深度了解行业的特性,其实当我们 ...

  6. proe常用c语言语句,带你轻松搞懂Proe条件语句

    原标题:带你轻松搞懂Proe条件语句 本文通过几个简单的例子介绍Proe中的条件语句,希望对你能有所帮助.Proe中使用的IF条件语句和C语言中的IF语句原理是一样的,其结构稍有差别.首先我们了解一下 ...

  7. 尚硅谷Nginx新版升级教程,带你轻松掌握高并发系统架构

    摘要:桃李春风一杯酒,江湖夜雨十年灯. "你说有没有一种可能, "你喜欢我,又不好意思说出口, "其实你可以直接说出来的, "我会让你知道什么叫心想事成.&qu ...

  8. 【2022 CCF BDCI 文心大模型创意项目】中秋款文心带你轻松搞定MV制作

    [2022 CCF BDCI 文心大模型创意项目]中秋款文心带你轻松搞定MV制作 项目效果先知 项目地址: https://aistudio.baidu.com/aistudio/projectdet ...

  9. 带你们轻松玩遍吃遍张家界

    来张家界的朋友一般都会去的景点是国家森林公园.天门山.玻璃桥.凤凰等等,玩遍这些景点至少需要4天-5天的时间.很多朋友虽然想一次性玩遍张家界的各大景点,但是由于时间.距离关系,只能选取几个最想去的地方 ...

最新文章

  1. Python中的pandas模块学习
  2. Android --- 使用纯java代码实现相对布局(通俗易懂)
  3. ABAP模块P类型详细解释
  4. 2021-01-14
  5. NET中解决KafKa多线程发送多主题的问题
  6. 训练日志 2019.1.19
  7. Linux 问题故障定位,看这一篇就够了
  8. ubantu中怎样安装VMware Tools
  9. MFC 教程【10_内存分配方式和调试机制 】
  10. Opencv之获取边缘和画轮廓
  11. 国科大学习资料--模式识别与机器学习(黄庆明)--期末复习题1(含答案)
  12. 扒一扒网易云课堂python课程,发现还有不少可以白嫖的免费好资源
  13. ZN-IRF02工业机器人视觉分拣实训系统
  14. Python第三方库matplotlib(2D绘图库)入门与进阶
  15. IOS Appstore 预览图尺寸
  16. ff14优雷卡补正什么意思_如何评价FF14 禁地优雷卡?
  17. 2021开源免费CMS建站系统怎么选择?
  18. 物联卡显示停用是怎么回事?物联网卡这些状态你都了解吗
  19. 光电显示技术 2 阴极射线管显示技术
  20. 分享一下QII10.1河蟹文件

热门文章

  1. python import random 报错_导致python中import错误的原因是什么
  2. termux 的lxml下载
  3. 单词倒排 与 IP整数转换
  4. Three.js《踩坑日记1》
  5. 产品有复杂的卡扣倒扣,我们如何设计模具结构?
  6. 如何清洁AirPods、AirPods Pro、AirPods Max 和 EarPods?
  7. ps3能装linux上网,上百度聊QQ 装Linux让你的PS3无所不能
  8. Jeecg-Boot简介
  9. 基于 OE、Yocto、Arago 构建 TI 板卡的定制文件系统
  10. html圆形波浪流量统计,HTML-波浪水球