全排列问题

日升时奋斗,日落时自省 

目录

1、全排列

2、全排列II

3、子集

4、组合


1、全排列

首先要了解全排列是怎么样的

例如:数组[1,2,3]的全排列(全排列就是不同顺序排列方式)

例子所有的排列方式如:[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]六种

画个图来解释一下:

代码:

    List<List<Integer>> result;  //终态 结果
    List<Integer> path;  //每条路径的结果
    public List<List<Integer>> permute(int[] nums) {
        result=new ArrayList<>();
        path=new ArrayList<>();
        int n=nums.length;
        if(n==0){
            return result;
        }
        //标记位
        boolean[] vis=new boolean[n];
        //参数  数组 当前层数  数组个数 标记位
        bfs(nums,0,n,vis);
        return result;
    }
    public void bfs(int[] nums,int index,int len,boolean[] vis){
        //层数等于数组个数表示路径已经收集齐一次 进行终态添加
        if(index==len){
            result.add(new ArrayList<>(path));
            return ;
        }
        //每层都会进行整个数组的遍历
        for(int i=0;i<len;i++){
            //但是需要判断标记位 该数字是否被标记使用,这里需要是没有使用过的数字
            if(!vis[i]){
                //进来后就算是被使用了, 进行标记一下
                vis[i]=true;
                //同时添加到路径中
                path.add(nums[i]);
                //进行下一层 遍历
                bfs(nums,index+1,len,vis);
                //如果下一层进行失败 当前层的该数也没有用了,因为这条路走不通
                //标记位删除的标记
                vis[i]=false;
                //同时删除当前数位
                path.remove(path.size()-1);
            }
        }

    }

2、全排列II

题目来源:. - 力扣(LeetCode)

题目的主要目的就是让全排列不要重复,重复的就不要写出来了

首先我们想前后一样就不选了,但是这个是需要一个前置条件的,需要给数组排个序

去重条件就是 nums[i]!=nums[i-1]并且当前位置标记位为false(说明没有选过)为进入条件

条件代码:!check[i]&&nums[i]!=nums[i-1]    (但是这样是不行的)

注:i-1是会越界的

再次修改的条件代码:!check[i]&&(i==0||nums[i]!=nums[i-1])

注:其实还是不完全的,如果同一层的check的上一个(check[i-1])为true说明选过了,此时nums[i]==nums[i-1],我们选还是不选,当然是选

其实全排列的规律就是  1(1)2(2)2(3)   1(1)2(3)2(2)   其实这里就相当于我们选了(1)(2)(3) 这种情况

放弃了(1)(3)(2)这种类似情况

注:这里红括号表示层数

方法一:

代码:

    List<List<Integer>> ret;    //终态集
    List<Integer> path;         //结果集
    boolean[] check;
    public List<List<Integer>> permuteUnique(int[] nums) {
        ret=new ArrayList<>();
        path=new ArrayList<>();
        check=new boolean[nums.length]; //标记位
        Arrays.sort(nums); //排序 为去重做的准备
        dfs(nums,0);
        return ret;
    }
    public void dfs(int[] nums,int pos){
        //终态条件
        if(path.size()==nums.length){
            ret.add(new ArrayList<>(path));
            return ;
        }
        for(int i=0;i<nums.length;i++){
            //当前标记位==false  &&   (i不能越界||前后不相等||同层上一个为true)
            if(!check[i]&&(i==0||nums[i]!=nums[i-1]||check[i-1])){
                path.add(nums[i]);
                check[i]=true;
                dfs(nums,pos+1);
                path.remove(path.size()-1);
                check[i]=false;
            }
        }
    }

方法二:

如果觉得上述代码比较难以接受的话的,只要理解全排列就行,这里可以使用其他集合来处理去重问题例如使用Set来去重

    List<List<Integer>> ret;
    List<Integer> path;
    boolean[] check;
    public List<List<Integer>> permuteUnique(int[] nums) {
        ret=new ArrayList<>();
        path=new ArrayList<>();
        check=new boolean[nums.length];
        Arrays.sort(nums);
        dfs(nums,0);
        //创建set集合
        Set<List<Integer>> set=new HashSet<>();
        //添加后进行去重
        for(int i=0;i<ret.size();i++){
            set.add(ret.get(i));
        }
        //清除ret原来的值
        ret.clear();
        //重新将去重后的数据进行添加
        for(List<Integer> tmp:set){
            ret.add(tmp);
        }
        return ret;
    }
    public void dfs(int[] nums,int pos){
        if(path.size()==nums.length){
            ret.add(new ArrayList<>(path));
            return ;
        }
        for(int i=0;i<nums.length;i++){
            if(!check[i]){
                path.add(nums[i]);
                check[i]=true;
                dfs(nums,pos+1);
                path.remove(path.size()-1);
                check[i]=false;
            }
        }
    }

3、子集

题目来源:LCR 079. 子集 - 力扣(LeetCode)

子集就是我们在数学里理解的意思:

[1,2,3]的子集就是[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]

图示:

注:当前层到下一层的位置都会+1

代码:

    List<List<Integer>> ret;   //终态集
    List<Integer> path;       //结果集(路径集)
    public List<List<Integer>> subsets(int[] nums) {
        ret=new ArrayList<>();
        path=new ArrayList<>();
        dfs(nums,0);
        return ret;
    }

    private void dfs(int[] nums, int pos) {
        //子集  是  每次都会进行添加
        ret.add(new ArrayList<>(path));
        //当前层的位置 是上层位置+1   pos就是上层位置+1来的
        for(int i=pos;i<nums.length;i++){
            path.add(nums[i]);
            //递推条件就是数组 和 下层的下一个位置
            dfs(nums,i+1);
            path.remove(path.size()-1);
        }
    }

4、组合

题目来源:77. 组合 - 力扣(LeetCode)

子集的升级版(个人是这么理解的)

给定一个数n和一个组合个数k

n=4 ,k=2

其实就是让我们把[1,2,3,4]进行组合:

结果为:[1,2],[1,3],[1,4],[2,3],[2,4],[3,4] (其实是有点像子集的只是稍微加了点处理)

子集没有限定条件来添加结果集,这里添加了条件是 当结果集为k 的时候添加到终态集中

这里还是拿n=3,k=2再来举一个例子会更清楚些

其实就是让我们把[1,2,3]进行组合:

结果为:[1,2],[1,3],[2,3]

图示:

代码:

其实仔细看看也就是只有条件边了,其他都没有改变

    List<List<Integer>> ret;
    List<Integer> path;
    int num,key;  //设置为全局变量方便获取,不用通过传参来使用
    public List<List<Integer>> combine(int n, int k) {
        ret=new ArrayList<>();
        path=new ArrayList<>();
        num=n;
        key=k;
        dfs(1);
        return ret;
    }
    public void dfs(int pos){
        //限定结果集的个数为k
        if(path.size()==key){
            ret.add(new ArrayList<>(path));
            return;
        }
        for(int i=pos;i<=num;i++){
            path.add(i);
            dfs(i+1);
            path.remove(path.size()-1);
        }
    }

注:如果友友们还是感觉有点陌生我换个方法来看看

    List<List<Integer>> ret;
    List<Integer> path;
    int n,key;  //设置为全局变量方便获取,不用通过传参来使用
    public List<List<Integer>> combine(int[] nums, int k) {
        ret=new ArrayList<>();
        path=new ArrayList<>();
        key=k;
        dfs(nums,0);
        return ret;
    }
    public void dfs(int[] nums,int pos){
        //限定结果集的个数为k
        if(path.size()==key){
            ret.add(new ArrayList<>(path));
            return;
        }
        for(int i=pos;i<nums.length;i++){
            path.add(nums[i]);
            dfs(nums,i+1);
            path.remove(path.size()-1);
        }
    }

注:这个题目是稍微改动了一下,作为例题来看,是不是就和子集很相似,就是变了个条件

总结:知道全排列,子集和组合不一定是为了这几个题,这些方法有时候更像是枚举的形式出现,可以作为地基,稍作改善很多题就在一个小范围内进行解决 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/547238.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode876_链表的中间结点

1.leetcode原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 2.题目描述 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5…

PTA 编程题(C语言)-- 判断素数

题目标题&#xff1a; 判断素数 题目作者 陈越 浙江大学 本题的目标很简单&#xff0c;就是判断一个给定的正整数是否素数。 输入格式&#xff1a; 输入在第一行给出一个正整数N&#xff08;≤ 10&#xff09;&#xff0c;随后N行&#xff0c;每行给出一个小于…

康耐视visionpro-CoglntersectLineLineTool操作说明工具详细说明

◆CogIntersectLineLineTool功能说明&#xff1a; 创建两条线的交点 备注&#xff1a;在“Geometry-Intersection”选项中的所有工具都是创建两个图形的交点工具&#xff0c;其中包括圆与圆的交点、线与圆的交点、线与线的交点、线与圆的交点等&#xff0c;工具使用的方法相似。…

C++ - set 和 map详解

目录 0. 引言 1. 关联式容器 2. 键值对 3. 树形结构 4. set 4.1 set 的定义 4.2 set 的构造 4.3 set 的常用函数 4.4 set 的特点 5. multiset 5.1 multiset 插入冗余数据 5.2 multiset - count 的使用 6. map 6.1 map 的定义 6.2 map 的构造 6.3 map的常…

dcoker+nginx解决前端本地开发跨域

步骤 docker 拉取nginx镜像跑容器 并配置数据卷nginx.conf nginx.conf文件配置 这里展示server server {listen 80;listen [::]:80;server_name localhost;#access_log /var/log/nginx/host.access.log main;location / {# 当我们访问127.0.0.1:8028就会跳转到ht…

软件2班20240415

快速引用类选择器 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevi…

二进制离散无记忆对称信道

目录 引言 二进制离散无记忆对称信道 引言 在无线通信中&#xff0c;信源与信宿是分开的&#xff0c;两者间的通信环境的复杂度通常会随着距离 的增加而提升。信道是用来连接信源与信宿的媒介。信源与信宿之间的信息传递则需要 借助于信道&#xff0c;因此信道质量的优劣通常…

移动端web适配方案

以下是移动端适配的多个方案&#xff0c;也可以说说你是怎么做的。 正文 自适应&#xff1a;根据不同的设备屏幕大小来自动调整尺寸、大小 响应式&#xff1a;会随着屏幕的实时变动而自动调整&#xff0c;是一种更强的自适应 为什么要做移动端适配&#xff1f; 目前市面上…

【深度剖析】曾经让人无法理解的事件循环,前端学习路线

先自我介绍一下&#xff0c;小编浙江大学毕业&#xff0c;去过华为、字节跳动等大厂&#xff0c;目前阿里P7 深知大多数程序员&#xff0c;想要提升技能&#xff0c;往往是自己摸索成长&#xff0c;但自己不成体系的自学效果低效又漫长&#xff0c;而且极易碰到天花板技术停滞…

Redis入门到通关之ZSet命令

文章目录 ⛄概述⛄常见命令有⛄RedisTemplate API❄️❄️ 向集合中插入元素&#xff0c;并设置分数❄️❄️向集合中插入多个元素,并设置分数❄️❄️按照排名先后(从小到大)打印指定区间内的元素, -1为打印全部❄️❄️获得指定元素的分数❄️❄️返回集合内的成员个数❄️❄…

最优算法100例之49-链表环-计算环的长度

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 定义两个指针,一个指针走两步,一个指针走一步,第一次相遇时开始计数,第二次相遇时停止计数,最后计数器的值就是环的长度…

STM32H7上实现AD5758驱动

目录 概述 1 下载ADI 5758 Demo 2 AD5758驱动的移植 2.1 使用STM32CubeMX创建工程 2.2 接口函数实现 2.2.1 驱动接口列表 2.2.2 函数实现 2.2.3 修正ad5758驱动 3 AD5758应用程序 3.1 编写测试程序 3.1.1 配置参数结构 3.1.2 配置参数函数 3.1.3 读取参数函数 3.…

【max材质addtive叠加模式特效渲染不出通道的解决办法】

max材质addtive叠加模式特效渲染不出通道的解决办法 2021-12-22 18:15 max的scanline扫描线&#xff0c;vray渲染可以&#xff0c;红移不行(只支持它自己的材质&#xff0c;它自己的材质没有additive模式)。据说mr是可以的。 右侧的球体使用附加不透明度。 附加不透明度通过将…

CentOS:执行make命令时报错g++: Command not found

报错截图&#xff1a; 其实很简单只需要安装一下 yum -y install gcc automake autoconf libtool make yum install gcc gcc-c

​LeetCode解法汇总2924. 找到冠军 II

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 一场比赛中共有 n 支队伍&#xff0c;按从…

J垃圾回收

J垃圾回收 1 概述2 方法区的回收3 如何判断对象可以回收3.1 引用计数法3.2 可达性分析法 4 常见的引用对象4.1 软引用4.2 弱引用4.3 虚引用4.4 终结器引用 5 垃圾回收算法5.1 垃圾回收算法的历史和分类5.2 垃圾回收算法的评价标准5.3 标记清除算法5.4 复制算法5.5 标记整理算法…

【深入理解】width 的默认值,2024年最新面试复盘

先自我介绍一下&#xff0c;小编浙江大学毕业&#xff0c;去过华为、字节跳动等大厂&#xff0c;目前阿里P7 深知大多数程序员&#xff0c;想要提升技能&#xff0c;往往是自己摸索成长&#xff0c;但自己不成体系的自学效果低效又漫长&#xff0c;而且极易碰到天花板技术停滞…

如何使用pytorch进行图像分类

如何使用pytorch进行图像分类https://featurize.cn/notebooks/5a36fa40-490e-4664-bf98-aa5ad7b2fc2f

实时传输,弹性优先——物联网通讯打造数据上传新标杆

随着信息技术的飞速发展&#xff0c;物联网技术已经成为连接物理世界和数字世界的桥梁。在物联网领域&#xff0c;数据上传的速度、稳定性和灵活性是评价通讯技术优劣的重要指标。近年来&#xff0c;物联网通讯在实时传输、弹性优先方面取得了显著进展&#xff0c;为数据上传树…

224 基于matlab的优化工具箱优化函数

基于matlab的优化工具箱优化函数&#xff0c; 此工具箱中提供的算法包括&#xff1a; 灰狼优化器&#xff08;GWO&#xff09;&#xff0c;蚂蚁狮子优化器&#xff08;ALO&#xff09;&#xff0c;多功能优化器&#xff08;MVO&#xff09;&#xff0c;蜻蜓算法&#xff08;DA&…