47. 全排列 II

news2024/9/21 4:38:35

关上过去和未来的铁门,活在“今天”这个舱室中。                                 ——《人性的优点》

47. 全排列 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

思路:(回溯)

此题是 46. 全排列 的进阶

  • 但是这道题有了一点改变,那么就是列表里面有重复数字,全排列的结果,相同答案只算一种,那么我们就要考虑重复。
  • 当然因为题目没有说该队列有序,所以要先排序。

判断的时候加上:

if(i > 0 && nums[i] == nums[i-1] && hasVisited[i-1] == false) {
	continue;
}

其中最为关键的是 hasVisited[i-1] == false ,用来去重,就是限制一下两个相邻的重复的访问顺序

举个栗子 :

对于两个相同的数 1 1 ,我们将其命名为 a b,a 表示第一个 1 ,b 表示第二个 1

  • 如果不去重得的话,会有两种重复排列 a b,b a ,我们只需取其中任意一种排列即可;
  • 为了达到目的,限制一下 a ,b 的访问顺序即可;
  • 比如 我们只取 a b 这个排列的话,只有当 nums[i - 1] 访问后,我们才去访问 nums[i] ,
  • 也就是说 如果 hasVisited[i-1] == false 的话, 则 continue 跳过。

举另个栗子 :

去重最为关键的代码为:

if(i > 0 && nums[i] == nums[i-1] && hasVisited[i-1] == false) {
	continue;
}

但如果改成 hasVisited[i-1] == true ,也是正确的, 去重代码如下:

if(i > 0 && nums[i] == nums[i-1] && hasVisited[i-1] == true) {
	continue;
}

这是为什么呢?

  • hasVisited[i-1] == false ,是对树层中前一位去重;
  • hasVisited[i-1] == true ,是对树枝前一位去重;

(借用一下别人的图进行理解):

如果 是三个相同的数 1 1 1

树层上去重(hasVisited[i-1] == false),树形结构如下:
在这里插入图片描述
树枝上去重(hasVisited[i-1] == true),树形结构如下:
在这里插入图片描述
观察上图可以得出:

  • 树层上对前一位去重非常彻底,效率很高;
  • 树枝上对前一位去重虽然最后可以得到答案,但是做了很多无用搜索。

代码:(Java)

import java.util.ArrayList;
import java.util.List;

public class all_permute {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		int [] nums = {1, 1, 2};
		System.out.println(permuteUnique(nums));
	}
	public static List<List<Integer>> permuteUnique(int[] nums) {
		List<List<Integer>> permutes = new ArrayList<>();
		List<Integer> permute = new ArrayList<>();
		if(nums == null || nums.length == 0) {
			return permutes;
		}
		int flag = 0;//标记
		for(int i = 1; i < nums.length ; i++) {//冒泡排序
			for(int j = 0; j < nums.length - i; j++) {
				if(nums[j] > nums[j+1]) {
					int temp = nums[j];
					nums[j] = nums[j+1];
					nums[j+1] = temp;
					flag++;
				}
			}
			if(flag == 0)
				break;
		}
		boolean [] hasVisited = new boolean[nums.length];
		backTracking(nums, hasVisited, permute, permutes);
		return permutes;
	}
	private static void backTracking(int[] nums, boolean[] hasVisited, List<Integer> permute, List<List<Integer>> permutes) {
		// TODO 自动生成的方法存根
		if(permute.size() == hasVisited.length) {
			permutes.add(new ArrayList<>(permute));
			return;
		}
		for(int i = 0; i < nums.length; i++) {
			if(hasVisited[i]) {
				continue;
			}
			if(i > 0 && nums[i] == nums[i-1] && hasVisited[i-1] == false) {
				continue;
			}
			hasVisited[i] = true;
			permute.add(nums[i]);
			backTracking(nums, hasVisited, permute, permutes);
			permute.remove(permute.size() - 1);
			hasVisited[i] = false;
		}
	}
}

运行结果:

在这里插入图片描述

复杂度分析:

  • 时间复杂度: O ( n × n ! ) O(n×n!) O(n×n!),其中 n 为序列的长度。

    • 算法的复杂度首先受 backTracking 的调用次数制约,backTracking 的调用次数为 ∑ k = 1 n P ( n , k ) \sum_{k=1}^{n} P(n, k) k=1nP(n,k)次,其中 P ( n , k ) = n ! ( n − k ) ! = n ( n − 1 ) … ( n − k + 1 ) P(n, k)=\frac{n !}{(n-k) !}=n(n-1) \ldots(n-k+1) P(n,k)=(nk)!n!=n(n1)(nk+1),该式被称作 n 的 k - 排列,或者部分排列。

    • ∑ k = 1 n P ( n , k ) = n ! + n ! 1 ! + n ! 2 ! + n ! 3 ! + … + n ! ( n − 1 ) ! < 2 n ! + n ! 2 + n ! 2 2 + n ! 2 n 2 < 3 n ! \sum_{k=1}^{n} P(n, k)=n !+\frac{n !}{1 !}+\frac{n !}{2 !}+\frac{n !}{3 !}+\ldots+\frac{n !}{(n-1) !}<2 n !+\frac{n !}{2}+\frac{n !}{2^{2}}+\frac{n !}{2^{n} 2}<3 n ! k=1nP(n,k)=n!+1!n!+2!n!+3!n!++(n1)!n!<2n!+2n!+22n!+2n2n!<3n!
      , 这说明 backTracking 的调用次数是 O ( n ! ) O(n!) O(n!)的。

    • 而对于 backTracking调用的每个叶结点(最坏情况下没有重复数字共 n ! n! n!个),我们需要将当前答案使用 O ( n ) O(n) O(n)的时间复制到答案数组中,相乘得时间复杂度为 O ( n × n ! ) O(n×n!) O(n×n!)

    • 因此时间复杂度为 O ( n × n ! ) O(n×n!) O(n×n!)

  • 空间复杂度: O ( n ) O(n) O(n)。我们需要 O ( n ) O(n) O(n)的标记数组,同时在递归的时候栈深度会达到 O ( n ) O(n) O(n),因此总空间复杂度为 O ( n + n ) = O ( 2 n ) = O ( n ) O(n+n)=O(2n)=O(n) O(n+n)=O(2n)=O(n)

注:仅供学习参考!

题目来源:力扣

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

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

相关文章

蓝桥杯嵌入式AT24C02

文章目录前言一、AT24C02原理图二、IIC通信协议三、代码编写1.拷贝官方驱动程序2.编写AT24C02读写函数1.查看AT24C02芯片手册确定AT24C02器件地址2.读函数编写3.写函数编写4.代码使用总结前言 本文将带大家了解IIC协议&#xff0c;并带大家编写AT24C02的驱动代码。 一、AT24C…

MySQL-MHA高可用配置及故障切换

文章目录一、MHA概述二、MHA的组成1、MHA Node&#xff08;数据节点&#xff09;2、MHA Manager&#xff08;管理节点&#xff09;3、MHA 的特点四、搭建步骤实验思路实验操作故障模拟故障切换备选主库的算法一、MHA概述 MHA&#xff08;MasterHigh Availability&#xff09;是…

Java搭建宝塔部署实战毕设项目SpringBoot大学生就业信息管理源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 本期给大家带来一套Java开发的毕设项目SpringBoot大学生就业信息管理源码&#xff0c;适合拿来做毕业设计的同学。可以下载来研究学习一下&#xff0c;本期把这套系统分享给大家。 技术架构 技术框架&#xff1a…

(ICIP-2019)通过神经结构搜索进行视频动作识别

通过神经结构搜索进行视频动作识别 paper题目&#xff1a;VIDEO ACTION RECOGNITION VIA NEURAL ARCHITECTURE SEARCHING paper是奥卢大学发表在ICIP 2019的工作 paper地址&#xff1a;链接 ABSTRACT 深度神经网络在视频分析和理解方面取得了巨大成功。然而&#xff0c;设计高…

【Spring系列】- Spring循环依赖

Spring循环依赖 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 一个有梦有戏的人 怒放吧德德 &#x1f31d;分享学习心得&#xff0c;欢迎指正&#xff0c;大…

JMeter入门教程(11) --关联

文章目录1.任务背景2.任务目标3.任务实操1.任务背景 当JMeter执行脚本时&#xff0c;伪装成浏览器&#xff0c;然后根据脚本&#xff0c;把当初真的浏览器所发过的内容&#xff0c;再对网站服务器重新发送一遍&#xff0c;JMeter企图骗过服务器&#xff0c;让服务器以为它就是…

010. 递增子序列

1.题目链接&#xff1a; 491. 递增子序列 2.解题思路&#xff1a; 2.1.题目要求&#xff1a; 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 &#xff08;数组可能有重复的元素&#xff0c;相等的元素排…

IDOC的状态

这篇文章介绍IDOC Status的概念和它们的用途&#xff0c;明确IDOC status的类别&#xff0c;看一下完整的状态列表&#xff0c;包括INBOUND和OUTBOUND&#xff0c;还有入站和出站iDoc处理时iDoc状态的顺序。 另外还有监控SAP IDOC status的工具&#xff0c;比如AIF&#xff0c;…

推特营销引流入门指南

一、关注 当您关注另一个Twitter用户时&#xff0c;您进行订阅&#xff0c;即可立即阅读其内容分享。因此&#xff0c;请评估您关注的人&#xff0c;尤其是刚开始时。跟踪新用户的一种简单方法是找到他们的个人资料&#xff0c;然后单击“关注”按钮。 Twitter对于那些疯狂点…

机器学习笔记之受限玻尔兹曼机(三)推断任务

机器学习笔记之受限玻尔兹曼机——推断任务引言回顾&#xff1a;受限玻尔兹曼机的模型表示推断任务求解——后验概率(posterior)基于隐变量的后验概率求解基于观测变量的后验概率求解受限玻尔兹曼机与神经网络的联系引言 上一节介绍了受限玻尔兹曼机的模型表示(Representation…

C++图书管理系统(管理员-读者)

C图书管理系统&#xff08;管理员-读者&#xff09; 一、设计一款文字式交互的图书管理系统&#xff0c;要求具备注册登录、浏览图书、借还图书等基本功能&#xff1b; 二、要求以外部文件的形式存储书籍信息、馆藏记录、借阅记录、用户信息等。【可参考提供的书籍清单】 三…

如何批量查询搜狗收录?提升搜狗收录8个方法介绍

如何批量查询搜狗收录? 批量查询搜狗收录的具体流程如下&#xff1a; 1、打开站长工具 2、在域名输入框添加需要查询的域名 3、在功能选择区勾选需要查询的功能&#xff08;这里勾选搜狗是否收录&#xff0c;搜狗收录总数&#xff09; 4、提交查询&#xff0c;等待查询结果 …

Android样式和主题背景

简介&#xff1a; 本文将简单介绍Android样式与主题背景的相关内容 文章目录前言一、样式二、主题背景三、样式层次结构四、创建并应用样式五、自定义默认主题六、添加特定于版本的样式七、常见的主题风格总结前言 借助 Android 中的样式和主题背景&#xff0c;我们可以将应用…

十五管还原炉舟皿自动卸料单元

目  录 摘要 Ⅰ 1 绪论 1 1.1 十五管还原炉舟皿产生和发展 1 1.2十五管还原炉舟皿的今天与明天 2 2 总体方案设计 4 2&#xff0e;1自动卸料单元的作用 4 2&#xff0e;2十五管还原炉舟皿自动卸料单元结构的选择 4 2&#xff0e;3设计技术参数: 7 2&#xff0e;4 自动卸料单元…

Python实现基于物品的协同过滤推荐算法构建电影推荐系统

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 基于物品的协同过滤推荐&#xff08;Item-based CF&#xff09;的假设原理为&#xff1a;跟你喜欢的东西…

python的数据可视化

python画图1.使用pyecharts画图1.1 画地图1.1.1 画2D中国地图1.1.2 画2D世界地图1.1.3 画3D世界地图1.2 pyecharts的三种图片渲染工具1.2.1 snapshot_selenium1.2.2 snapshot_phantomjs1.2.3 snapshot_pyppeteer1.3 词云图1.3.1依据图片渲染出指定形状的词云图1.3.2渲染出指定大…

基于Android的学生信息管理App设计(Android studio开发)

目 录 一、 题目选择&#xff08;题目、选题意义&#xff09; 3 二、 设计目的 3 1、 初衷 3 2、 结合实际 3 3、 使用工具 3 三、 最终页面效果展示 4 1、 登陆界面 4 2、 主界面 5 3、 各个功能模块 6 四、 各部分设计 11 1、活动页面Activity布局文件 11 2、Activity的编程 …

基于JSP网上书城的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

Figma UI UX设计教程

Figma UI UX设计教程 使用 Figma 获得 UI 设计、用户界面、用户体验设计、UX 设计和网页设计方面的工作 课程英文名&#xff1a;Figma UI UX Design Essentials 此视频教程共10.0小时&#xff0c;中英双语字幕&#xff0c;画质清晰无水印&#xff0c;源码附件全 下载地址 课…

毕业设计-基于机器视觉的行人车辆跟踪出入双向检测计数

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…