力扣第四十七题——全排列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
完整代码
int* vis;void backtrack(int* nums, int numSize, int** ans, int* ansSize, int idx, int* perm) {if (idx == numSize) {int* tmp = malloc(sizeof(int) * numSize);memcpy(tmp, perm, sizeof(int) * numSize);ans[(*ansSize)++] = tmp;return;}for (int i = 0; i < numSize; ++i) {if (vis[i] || (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])) {continue;}perm[idx] = nums[i];vis[i] = 1;backtrack(nums, numSize, ans, ansSize, idx + 1, perm);vis[i] = 0;}
}int cmp(void* a, void* b) {return *(int*)a - *(int*)b;
}int** permuteUnique(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {int** ans = malloc(sizeof(int*) * 2001);int* perm = malloc(sizeof(int) * 2001);vis = malloc(sizeof(int) * numsSize);memset(vis, 0, sizeof(int) * numsSize);qsort(nums, numsSize, sizeof(int), cmp);*returnSize = 0;backtrack(nums, numsSize, ans, returnSize, 0, perm);*returnColumnSizes = malloc(sizeof(int) * (*returnSize));for (int i = 0; i < *returnSize; i++) {(*returnColumnSizes)[i] = numsSize;}return ans;
}
思路详解
整体思路
- 排序:首先对数组进行排序,以便在后续过程中可以轻松跳过重复的数字。
- 回溯:使用回溯算法生成所有可能的全排列。
- 去重:在生成全排列的过程中,通过一个布尔数组
vis来标记某个数字是否已经被使用,以及通过比较相邻数字是否相等来跳过重复的排列。
详细步骤
1. 排序函数cmp
cmp函数是一个比较函数,用于qsort函数进行排序。它比较两个整数的值,并返回它们之间的差值。
2. 主函数permuteUnique
- 初始化:分配内存给结果数组
ans、排列数组perm和访问标记数组vis。 - 排序:调用
qsort对输入数组nums进行排序。 - 调用回溯函数:调用
backtrack函数开始生成全排列。 - 设置返回列大小:为每个排列分配列大小,即
numsSize。
3. 回溯函数backtrack
- 终止条件:当
idx等于numSize时,表示一个排列已经生成完毕,将其复制到结果数组ans中。 - 遍历数组:遍历输入数组
nums,尝试将每个数字放入当前排列的idx位置。 - 剪枝:如果当前数字已经被访问过,或者当前数字与前一个数字相同且前一个数字未被访问过,则跳过当前循环,以避免生成重复的排列。
- 递归:将当前数字标记为已访问,并将其放入排列数组
perm中,然后递归调用backtrack函数处理下一个位置。 - 撤销选择:在递归返回后,将当前数字标记为未访问,以便在后续的迭代中可以重新使用。
代码亮点
- 去重:通过排序和比较相邻数字,巧妙地避免了生成重复的排列。
- 回溯算法:使用回溯算法高效地生成所有可能的全排列。
- 内存管理:动态分配和释放内存,以存储生成的排列和访问标记。
知识点精炼
-
排序:
- 使用
qsort函数对数组进行排序,以便于后续去重操作。
- 使用
-
回溯算法:
- 利用回溯算法遍历所有可能的组合,并在满足条件时生成全排列。
-
去重策略:
- 通过排序和相邻元素比较,避免在回溯过程中生成重复的排列。
-
布尔数组:
- 使用布尔数组
vis记录每个元素是否已被使用,确保每个元素在每个排列中只出现一次。
- 使用布尔数组
-
动态内存分配:
- 动态分配内存以存储全排列结果
ans、排列数组perm和访问标记数组vis。
- 动态分配内存以存储全排列结果
-
剪枝优化:
- 在回溯过程中,通过剪枝操作跳过不可能生成有效排列的分支,提高算法效率。
-
递归与迭代:
- 结合递归和迭代,实现深度优先搜索(DFS)来生成全排列。
-
内存释放:
- 在递归返回时,恢复现场,释放不必要的资源,避免内存泄漏。
-
比较函数:
- 实现
cmp比较函数,作为qsort的参数,用于数组元素的排序。
- 实现
-
返回值与参数:
- 通过指针参数返回全排列结果及其大小,以及每个排列的列大小。
优化方案
去重优化
- 排序后去重:在回溯之前先对数组进行排序,这样可以在生成排列时更容易地跳过重复的元素。
- 位运算去重:对于小范围的整数,可以使用位运算来标记已访问的元素,减少内存使用和提高访问速度。
2. 回溯剪枝
- 提前终止:在递归过程中,如果发现某个分支不可能生成有效排列,应立即终止该分支的递归。
- 按字典序排列:在回溯时,保持元素按字典序排列,可以更早地发现重复并剪枝。
3. 数据结构优化
- 原地交换:使用原地交换而非额外的数组来存储排列,可以减少内存使用和复制操作。
- 栈代替递归:将递归改为使用栈,可以减少函数调用的开销。
4. 算法优化
- 迭代而非递归:在某些情况下,迭代可能比递归更高效,因为它避免了函数调用的开销。
- 分支限界:使用分支限界技术,只生成那些有希望成为有效排列的分支。
5. 并行计算
- 多线程:对于大型问题,可以使用多线程并行生成排列的不同分支。
- 分布式计算:将问题分割成多个子问题,在分布式系统中并行解决。
6. 编译器优化
- 编译器优化选项:使用编译器的优化选项,如-O2或-O3,可以自动进行某些优化。
相关文章:
力扣第四十七题——全排列II
内容介绍 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。 示例 1: 输入:nums [1,1,2] 输出: [[1,1,2],[1,2,1],[2,1,1]]示例 2: 输入:nums [1,2,3] 输出:[[1,2,3],…...
Springer旗下中科院2区TOP,国人优势大!
关注GZH【欧亚科睿学术】,第一时间了解期刊最新动态! 1 通信网络类 【期刊简介】IF:4.0-5.0,JCR1区,中科院3区 【出版社】ELSEVIER出版社 【检索情况】SCIE&EI双检,CCF-C类 【征稿领域】通信网络的…...
【C++】C++入门知识详解(下)
大家好~我们接着【C】C入门知识详解(上)-CSDN博客来介绍另一些C入门基础知识。 1.缺省值和缺省参数 缺省参数就是声明或定义函数时为函数的参数指定一个缺省参数。在调用该函数时,如果没有指定实参,则采用该形参的缺省值…...
分压电阻方式的ADC电压校准
无人机有个流程是电池电压校准。具体做法是:让你用万用表测量一下电池两端的电压,然后输入到文本框中,电机计算能重新计算出电压分压器的值,从而获得电池电压值。 这种方法实现的原理是这样的: 电阻分压检测电压原理,以上图为例: 当电路确定时,R2/(R1+R2)是一个定值R,…...
使用Postman测试API短轮询机制:深入指南
短轮询是一种Web开发中常用的技术,用于在客户端和服务器之间定期检查更新。与长轮询或WebSockets等技术相比,短轮询简单易实现,但可能带来较多的HTTP请求,从而增加服务器负担。Postman作为一个强大的API测试工具,可以用…...
明清进士人数数据
明清进士人数数据 指标:省份名称、城市名称、区县名称、明清各省进士人数、明清各城市进士人数、明清各县区进士人数 指标说明: Province[省份名称]-统计数据所属省份 City[城市名称]-统计数据所属地级市 Region[区县名称]-统计数据所属区县 MQpro…...
C# 串口通信(通过serialPort控件发送及接收数据)
连接串口 界面设计打开串口发送数据通过文件发送发送数据 接收数据 首先可以在 工具箱中搜索serialport,将控件拖到你的Winfrom窗口。 界面设计 打开串口 private void Connect_Click(object sender, EventArgs e){serialPort1.PortName comboBox2.Text;//端口名s…...
数据安全的新盾牌:SQL Server数据库镜像技术详解
数据安全的新盾牌:SQL Server数据库镜像技术详解 在数据驱动的商业世界中,数据库的安全性是维护企业运营的关键。SQL Server提供了多种数据保护机制,其中数据库镜像技术是一个强大的高可用性解决方案,它可以显著提高数据的安全性…...
【C语言版】数据结构教程(一)绪论(上)
【内容简介】本文整理数据结构(C语言版)相关内容的复习笔记,供各位朋友借鉴学习。本章内容更偏于记忆和理解,请读者们耐心阅读。 数据结构教程 绪论(上) 本节学习目标 1.1 基本概念 1.2 抽象数据类型的表示…...
酒后为什么总感觉渴?
喝酒后感到口渴,这种感觉其实很常见。这主要是因为酒精对我们的身体有几种影响。首先,酒精能够扩张血管,这会加快血液循环,让肾脏更加活跃,产生更多的尿液。这样一来,我们体内的水分就会通过排尿流失&#…...
Docker安装OwnCloud私有云盘对接ceph
一、安装OwnCloud 我的安装包链接:https://pan.baidu.com/s/1cJO8WEonsw4gGQWgQaYzpw?pwd6bak 提取码:6bak 启动OwnCloud容器,没有镜像会自动下载 docker run -d -p 80:80 -v /home/owncloud:/var/www/html --name owncloud --restartalway…...
创建了Vue项目,需要导入什么插件以及怎么导入
如果你不知道怎么创建Vue项目,建议可以看一看这篇文章 怎么安装Vue的环境和搭建Vue的项目-CSDN博客 1.在idea中打开目标文件 2.系在一个插件Vue.js 3.下载ELement UI 在Terminal中输入 # 切换到项目根目录 cd vueadmin-vue # 或者直接在idea中执行下面命令 # 安装element-u…...
abstract 关键字
在C#中,abstract 关键字是一个非常重要的特性,它用于定义抽象类和抽象成员(如方法、属性、索引器、事件或操作符)。使用 abstract 关键字的目的主要是为了提供一种机制,让基类能够指定一个或多个必须由派生类实现的方法…...
用Python编写你的网络监控系统详解
概要 在现代网络管理中,实时监控网络流量和状态是保证网络正常运行的关键。使用Python编写网络监控工具可以帮助管理员及时发现和解决网络问题。本文将详细介绍如何使用Python编写网络监控工具,包括基本概念、常用库及其应用场景,并提供相应的示例代码。 网络监控的基本概念…...
操作系统——虚拟内存
一、虚拟内存是什么? 虚拟内存类似一个桥梁,原来程序直接访问物理内存读取数据,现在程序直接访问虚拟内存,由虚拟内存再访问物理内存。 使用虚拟内存的好处: 隔离进程、提高内存使用安全性:每个进程直接…...
Zoom视频会议软件使用
Zoom 是一款广泛使用的视频会议软件,可以用于在线会议、网络研讨会、课堂教学、团队协作等。以下是使用 Zoom 的基本步骤和一些有用的技巧: 安装 Zoom 下载并安装: 访问 Zoom 下载页面。下载适用于你的操作系统(Windows, macOS, Linux, iOS, Android)的客户端。安装完成后…...
MVC软件设计模式及QT的MVC架构
目录 引言 一、MVC思想介绍 1.1 MCV模型概述 1.2 Excel的处理数据 1.3 MVC模式的优势 二、QT中的MVC 1.1 模型(Model) 1. QAbstractItemModel 2. QStringListModel 3. QStandardItemModel 4. QSqlTableModel 和 QSqlQueryModel 5. QAbstract…...
使用WSL通过SSH连接并运行图形界面程序
使用WSL通过SSH连接并运行图形界面程序 1. 在Windows上安装X服务器2. 配置并启动VcXsrv3. 在WSL Ubuntu中设置DISPLAY变量4. 从WSL Ubuntu连接到远程服务器5. 在远程服务器上设置DISPLAY变量6. 测试X11转发7. 运行您的安装程序注意事项 在Windows Subsystem for Linux (WSL) 上…...
柳湛宇-简历
...
6-1 从全连接层到卷积
我们之前讨论的多层感知机十分适合处理表格数据,其中行对应样本,列对应特征。 对于表格数据,我们寻找的模式可能涉及特征之间的交互,但是我们不能预先假设任何与特征交互相关的先验结构。 此时,多层感知机可能是最好的…...
基于LLM的Python脚本自我进化:构建AI驱动的代码优化框架
1. 项目概述:当Python脚本学会自我进化几年前,如果有人告诉我,我写的Python脚本能在我喝咖啡的时候自己给自己“打补丁”、优化逻辑,我肯定会觉得这是科幻小说里的情节。但今天,这已经是我日常工作流的一部分。这个项目…...
Universal Data Tool 新功能解析:骨骼姿态标注与数据格式转换实战
1. 项目概述:一个数据标注工具的进化最近在整理一个计算机视觉项目的数据集时,我又一次打开了Universal Data Tool(UDT)。这个工具我用了快两年了,从它早期版本支持基础的图像分类和物体检测框标注开始,就一…...
S2C如何以FPGA原型验证方案破解中国芯片设计团队的验证痛点
1. 从EDA巨头东迁,看一个被忽视的蓝海市场最近业内有个不大不小的新闻,Altium这家知名的电子设计自动化(EDA)公司把总部搬到了中国。这事儿引起了不少讨论,但说实话,它既不是第一个这么干的,也未…...
HUM4D数据集:无标记人体动作捕捉的挑战与评估
1. HUM4D数据集概述HUM4D是一个专门针对无标记人体动作捕捉技术评估的基准数据集,由计算机视觉研究团队开发。这个数据集的核心价值在于填补了现有动作捕捉基准在复杂场景下的空白——那些包含快速运动、严重遮挡、深度突变和身份混淆的真实挑战。在动作捕捉领域&am…...
MarkFlowy:基于智能感知的Markdown写作流工具设计与实现
1. 项目概述:一个为Markdown而生的高效写作流工具 如果你和我一样,每天的工作都离不开Markdown——写技术文档、整理项目笔记、构思博客文章,那你一定体会过那种在“专注写作”和“格式调整”之间反复横跳的痛苦。刚进入心流状态,…...
跨端三维GIS实战:uni-app集成Cesium.js的RenderJS方案解析
1. 为什么需要跨端三维GIS解决方案 最近几年三维GIS应用越来越普及,从传统的Web端到移动端APP,开发者都希望实现"一次开发,多端运行"的目标。uni-app作为跨端开发框架,天然具备这个优势。但当我们想在uni-app中集成Cesi…...
Cursor-Buddy:基于AI的Web界面语音交互与视觉引导助手
1. 项目概述与核心价值最近在捣鼓一个挺有意思的开源项目,叫cursor-buddy。简单来说,它是一个能“住”在你鼠标光标里的AI助手,专门为Web应用设计。想象一下,你在浏览一个复杂的后台管理系统或者一个数据看板,突然想找…...
面试被问烂的20道编程基础题,你必须全会,不然别去面试
文章目录前言一、Python基础篇(6道)1. Python中list和tuple有什么区别?2. Python 3.7之后普通dict已经有序了,那OrderedDict还有存在的必要吗?3. Python中的深拷贝和浅拷贝有什么区别?4. Python中的*args和…...
从学生成绩表到销售报表:手把手教你用ag-grid列组/行组构建复杂业务表格
企业级销售报表实战:用ag-grid行组与列组构建动态分析系统 当业务数据从Excel迁移到前端可视化系统时,开发团队常面临多维分析的挑战。某零售企业曾因无法实时查看"华东区→浙江省→杭州市"三级维度下的季度销售趋势,导致错失库存调…...
MILCOM 2011技术风向:软件定义无线电、GaN与宽带测试的军用射频演进
1. 展会现场直击:MILCOM 2011的技术脉搏作为一名在射频微波和测试测量领域摸爬滚打了十几年的工程师,我对MILCOM(军事通信会议)这类展会总有一种特殊的感情。它不像那些消费电子展那样光鲜亮丽,人头攒动,但…...
