lc46全排列——回溯

news2024/12/15 12:13:52

46. 全排列 - 力扣(LeetCode)

法1:暴力枚举

总共n!种全排列,一一列举出来放入list就行,关键是怎么去枚举呢?那就每次随机取一个,然后删去这个,再从剩下的数组中继续去随机选一个,依次类推直到为数组为0。

为了快,选择set,每选了一个,set里就删除一个,再继续从里面随机选。

Tip:int[]转换为set,利用stream流替代传统for循环

class Solution {
    List<List<Integer>> ans = null;

    public List<List<Integer>> permute(int[] nums) {
        ans = new ArrayList<List<Integer>>();

        //记录还未抽中的数组元素,技巧:用stream流代替传统循环
        Set<Integer> set = new HashSet<>(Arrays.stream(nums).boxed().toList());
        
        int n = nums.length;
        bruteForce(set, n, new ArrayList<>(n));
        
        return ans;
    }

    //n表示set还剩几个元素没抽,list表示这次随机抽取的全排列
    public void bruteForce(Set<Integer> set, int n, List<Integer> list) {
        //反正就剩最后一个了,不用随机抽了
        //不用0,是为了减少一次拷贝
        if(n == 1) {
            for(int num:set)
                list.add(num);
            ans.add(list);
            return;
        }

        for(int num:set) {
            //需要拷贝构造新的list和set
            List<Integer> newList = new ArrayList<>(list);
            newList.add(num);

            Set<Integer> newSet = new HashSet<>(set);
            newSet.remove(num);
            bruteForce(newSet, n - 1, newList);
        }
    }
}

本来枚举共n!个,bruteForce()方法本身只调用了n!(1*n*n-1*...*2)次,但因为每次要拷贝新的list和set(list和set加起来共n个元素),所以每次调用bruteForce前拷贝都需要O(n),所以算上拷贝时间复杂度公式应该为

T(n) = n*( n + T(n-1))

具体为多少,GPT说为O(n⋅n!)我不知道对不对...不会算...

很明显这样暴力枚举的话,中间变量,list和set很多,拷贝也花时间。所以才有了回溯算法进行优化。

法2:回溯

可以不拷贝list,而是先添加,遍历完这次排列后,再删除回溯复原,再开始下一个,这就是所谓的回溯吧。

注意每次最后要添加list的拷贝。不过new ArrayList<>(originArr)是浅拷贝,里面的每个属性仍指向同一个对象,不过这里无所谓,不需要深拷贝,本身Integer包装类也是不可变对象。

class Solution {
    List<List<Integer>> ans = null;

    public List<List<Integer>> permute(int[] nums) {
        ans = new ArrayList<List<Integer>>();

        //记录还未抽中的数组元素,技巧:用stream流代替传统循环
        Set<Integer> set = new HashSet<>(Arrays.stream(nums).boxed().toList());
        
        int n = nums.length;
        bruteForce(set, n, new ArrayList<>(n));
        
        return ans;
    }

    //n表示set还剩几个元素没抽,list表示这次随机抽取的全排列
    public void bruteForce(Set<Integer> set, int n, List<Integer> list) {
        //没了
        if(n == 0) {
            //这里添加的应是新的拷贝,不然所有添加的都是同一个list了
            ans.add(new ArrayList<Integer>(list));
            return;
        }

        Set<Integer> tmpSet = new HashSet<>(set);
        for(int num:tmpSet) {
            list.add(num);
            set.remove(num);
            bruteForce(set, n - 1, list);

            //然后回溯
            list.remove(list.size()-1);
            set.add(num);
        }
    }
}

但我这种还是得拷贝set来方便后面继续抽未选中过的。不够优化。

官解十分巧妙利用了list的未排列部分来作set,这样可以每次选择list的未排列部分作为下一个排列的 来替代 从set中选择下一个排列的,然后通过回溯复原。

class Solution {
    List<List<Integer>> ans = null;

    public List<List<Integer>> permute(int[] nums) {
        ans = new ArrayList<List<Integer>>();

        //stream流代替传统for循环
        List<Integer> list = new ArrayList<>(Arrays.stream(nums).boxed().toList());

        int n = nums.length;
        backTrack(list, n, 0);
        
        return ans;
    }

    //n表示总共多少个元素,arrangedN表示已经排好多少个了,同时也表示list下一个应该排的下标
    public void backTrack(List<Integer> list, int n, int arrangedN) {
        //没了
        if(arrangedN == n) {
            //这里添加的应是新的拷贝,不然所有添加的都是同一个list了
            ans.add(new ArrayList<Integer>(list));
            return;
        }

        for(int i = arrangedN; i<n;i++) {
            Collections.swap(list, arrangedN, i);
            backTrack(list, n, arrangedN+1);
            //回溯复原
            Collections.swap(list, arrangedN, i);
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在线设计平台:Axure新手的在线设计助手

Axure是一款在产品设计、用户体验和交互设计领域广泛使用的强大原型设计工具。它使设计师和产品经理能够迅速构建高保真原型&#xff0c;验证设计和功能&#xff0c;并进行用户测试。结合在线设计平台的协作特性&#xff0c;团队可以更高效地创建、分享和优化原型&#xff0c;加…

Burp与小程序梦中情缘

前言 在日常渗透工作中&#xff0c;有时需要对微信小程序进行抓包渗透&#xff0c;通过抓包&#xff0c;我们可以捕获小程序与服务器之间的通信数据&#xff0c;分析这些数据可以帮助我们发现潜在的安全漏洞&#xff0c;本文通过讲述三个方法在PC端来对小程序抓包渗透 文章目…

gpu硬件架构

1.简介 NVIDIA在视觉计算和人工智能&#xff08;AI&#xff09;领域处于领先地位&#xff1b;其旗舰GPU已成为解决包括高性能计算和人工智能在内的各个领域复杂计算挑战所不可或缺的。虽然它们的规格经常被讨论&#xff0c;但很难掌握各种组件的清晰完整的图景。 这些GPU的高性…

SpringCloud集成sleuth和zipkin实现微服务链路追踪

文章目录 前言技术积累spring cloud sleuth介绍zipkin介绍Zipkin与Sleuth的协作 SpringCloud多模块搭建Zipkin Server部署docker pull 镜像启动zipkin server SpringCloud 接入 Sleuth 与 Zipkinpom引入依赖 (springboot2.6)appilication.yml配置修改增加测试链路代码 调用微服…

OBS + SRS:打造专业级直播环境的入门指南

OBS SRS&#xff1a;打造专业级直播环境的入门指南 1. OBS简介2. OBS核心功能详解2.1 场景&#xff08;Scenes&#xff09;管理2.2 源&#xff08;Sources&#xff09;控制2.3 混音器功能2.4 滤镜与特效2.5 直播控制面板 3. OBS推流到SRS服务器配置指南3.1 环境准备3.2 OBS推流…

Ubuntu K8s

https://serious-lose.notion.site/Ubuntu-K8s-d8d6a978ad784c1baa2fc8c531fbce68?pvs74 2 核 2G Ubuntu 20.4 IP 172.24.53.10 kubeadmkubeletkubectl版本1.23.01.23.01.23.0 kubeadm、kubelet 和 kubectl 是 Kubernetes 生态系统中的三个重要组件 kubeadm&#xff1a; 主…

前端(六)浮动流

浮动流 文章目录 浮动流一、标准流二、浮动流 一、标准流 所谓网页布局就是网页排版的方式&#xff0c;css中有三种网页布局的方式&#xff1a;标准流、浮动流和定位流。 标准流也称文档流&#xff0c;这是浏览器默认的排版方式。标准流中网页的元素会按从左往右、从上往下的…

双内核架构 Xenomai 4 安装教程

Xenomai 4是一种双内核架构, 继承了Xenomai系列的特点&#xff0c;通过在Linux内核中嵌入一个辅助核心&#xff08;companion core&#xff09;&#xff0c;来提供实时能力。这个辅助核心专门处理那些需要极低且有界响应时间的任务。 本文将在官网教程(https://evlproject.org/…

【安全研究】某黑产网站后台滲透与逆向分析

文章目录 x01. 前言x02. 分析 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与…

【SH】微信小程序调用EasyDL零门槛AI开发平台的图像分类研发笔记

文章目录 微信小程序字符串字符串模板字符串拼接 上传图片编写JS代码编写wxml代码编写wxss代码 GET请求测试编写测试代码域名不合法问题 GET和POST请求测试编写JS代码编写wxml代码编写wxss代码 效果展示 微信小程序字符串 字符串模板 这是ES6引入的特性&#xff0c;允许你通过…

6.2 Postman接口收发包

欢迎大家订阅【软件测试】 专栏&#xff0c;开启你的软件测试学习之旅&#xff01; 文章目录 前言1 接口收发包的类比1.1 获取对方地址&#xff08;填写接口URL&#xff09;1.2 选择快递公司&#xff08;设置HTTP方法&#xff09;1.3 填写快递单&#xff08;设置请求头域&#…

数据链路层(Java)(MAC与IP的区别)

以太网协议&#xff1a; "以太⽹" 不是⼀种具体的⽹络, ⽽是⼀种技术标准; 既包含了数据链路层的内容, 也包含了⼀些物理 层的内容. 例如: 规定了⽹络拓扑结构, 访问控制⽅式, 传输速率等; 例如以太⽹中的⽹线必须使⽤双绞线; 传输速率有10M, 100M, 1000M等; 以太…

SpringBoot2+Vue2开发工作管理系统

项目介绍 在工作中使用的管理系统&#xff0c;可以随手记录一些笔记、可以汇总一些常用网站的链接、可以管理自己负责的项目、可以记录每日日报和查看历史日报、可以记录加班情况、可以记录报销内容、可以编写文章文档。 系统功能 我的笔记快捷入口项目管理今日日报我的日报…

软考中级-软件设计师通过心路经验分享

执念&#xff0c;第四次终于通过了 没买书&#xff0c;下班后每天2小时&#xff0c;四个2个月终于过了 学习经验&#xff1a; 1.下班后学习真的靠毅力&#xff0c;和上学的时候考证不是一个状态&#xff0c;大家要及时调整&#xff0c;否则过程很痛苦 2.失败三次的经验&#xf…

burp(2)利用java安装burpsuite

BurpSuite安装 burpsuite 2024.10专业版&#xff0c;已经内置java环境&#xff0c;可以直接使用&#xff0c; 支持Windows linux macOS&#xff01;&#xff01;&#xff01; 内置jre环境&#xff0c;无需安装java即可使用&#xff01;&#xff01;&#xff01; bp2024.10下载…

el-table 动态计算合并行

原始表格及代码 <el-table:data"tableData"class"myTable"header-row-class-name"tableHead" ><el-table-column prop"date" label"日期"> </el-table-column><el-table-column prop"name" …

【Tomcat】第二站:Tomcat通过反射机制运行项目

目录 前言 1. 动态资源&静态资源 1.1 为什么要区分&#xff1f; 1.2 静态资源 1.3 动态资源 1.4 如何判断 2. Tomcat优先动态 2.1 原因 3. Tomcat运行项目的流程 前言 我们在写项目时&#xff0c;在进行前后端交互时&#xff0c;都会创建一个servlet&#xff0c;然…

vue canvas 绘制选定区域 矩形框

客户那边文档相当的多&#xff0c;目前需要协助其将文档转为数据写入数据库&#xff0c;并与其他系统进行数据共享及建设&#xff0c;所以不得不搞一个识别的功能&#xff0c;用户上传PDF文档后&#xff0c;对于关键信息点进行识别入库&#xff01; 以下为核心代码&#xff0c…

[Pro Git#3] 远程仓库 | ssh key | .gitignore配置

目录 1. 分布式版本控制系统的概念 2. 实际使用中的“中央服务器” 3. 远程仓库的理解 4. 新建远程仓库 5. 克隆远程仓库 6. 设置SSH Key 实验 一、多用户协作与公钥管理 二、克隆后的本地与远程分支对应 三、向远程仓库推送 四、拉取远程仓库更新 五、配置Git忽略…

【Python网络爬虫笔记】11- Xpath精准定位元素

目录 一、Xpath 在 Python 网络爬虫中的作用&#xff08;一&#xff09;精准定位元素&#xff08;二&#xff09;应对动态网页&#xff08;三&#xff09;数据结构化提取 二、Xpath 的常用方法&#xff08;一&#xff09;节点选取&#xff08;二&#xff09;谓词筛选&#xff0…