子序列与全排列的区别?

可能大家听到这两个名词,似乎感觉有点相似,分不清楚,什么是子序列,什么是全排列。本期文章就来给大家捋清楚这两个是什么。Let’s go.

三道题:

  1. 打印一个字符串的全部子序列,包括空字符串。
  2. 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。链接
  3. 给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。链接

本期文章源码:GitHub

文章目录

  • 一、打印全部的子序列
  • 二、无重复值的全排列
  • 三、有重复值的全排列
    • 分支限界

一、打印全部的子序列

打印一个字符串的全部子序列,包括空字符串

解题之前,我们先来看看什么是子序列。 所谓子序列就是:抽取原字符串的一些字符,按照原字符串的顺序进行放置的新字符串。举个例子:

原字符串为abcde,它的子序列可能是abcabcebcde等等; 分解子序列三个字的意思是:1、一定是原字符串的一些字符,2、一定是有序的(原字符串是什么先后顺序,新字符串也是什么先后顺序)。

那怎么进行解题呢?我们不妨看下图:

理解了大致的思路,我们能够做出两种选择,那就是要和不要当前这个字符。现在我们来看代码

//方法一
//str,是调用这个方法时,直接通过字符串转化过来的
//i, 表示 当前在str数组的位置
//list, 是存放所有的子序列的
public void getSubsequence1(char[] str, int i, ArrayList<String> list) {if (i == str.length) {list.add(str.toString()); //转换为字符串,存储即可}getSubsequence(str, i + 1, list); //表示  要了当前位置的字符char tmp = str[i]; //临时存储字符str[i] = '\0'; //将该位置的字符改为\0getSubsequence(str, i + 1, list); //不要当前的字符str[i] = tmp; //恢复原来的样子
}
//方法二
//res  是本次循环的一次结果,最后将这个结果放入list里面
public static void getSubsequence2(char[] str, int i, ArrayList<String> list, StringBuilder res) {if (i == str.length) {list.add(res.toString());return;}res.append(str[i]); //要当前字符getSubsequence2(str, i + 1, list, res);res.delete(res.length() - 1, res.length()); //不要当前字符getSubsequence2(str, i + 1, list, res);}

上面两组代码都大同小异,整体是时间复杂度差不多,只是方法二需要的空间稍微多一点点。差别就在这。看大家觉得那种方法更好了!!!

二、无重复值的全排列

LeetCode链接

全排列:从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。

也就是说,给定一个字符串,每个字符,可以随便放在字符串的哪一个位置,这样组合起来的字符串,就是排列的。对比子序列来说,子序列的字符出现顺序,需要跟原字符出现的先后顺序一样。这也是二者的区别所在。

举例子:

至于如何表示剩下的字符,以及如何选择字符,我们来看代码,就能够理解了!!!

public List<List<Integer>> permute(int[] nums) {if (nums == null) {return null;}List<List<Integer>> res = new ArrayList<>();getFullPermute(nums, 0, res); //递归调用子过程return res;
}//nums, 是所有的数据。
//nums[0 ... i - 1] 范围内,是已经确定好的数据
//nums[i...] 范围上的数据,就是上图中,绿色框里面剩下的数据,还是待选择的状态
//res,就是最后的结果
private void getFullPermute(int[] nums, int i, List<List<Integer>> res) {if (i == nums.length) {ArrayList<Integer> tmp = new ArrayList<>();for (int data : nums) {tmp.add(data);}res.add(tmp);return;}//循环遍历剩下的数据for (int j = i; j < nums.length; j++) {swap(nums, i, j); //在剩下的数据中,选取一个,放到当前i位置,然后去做递归getFullPermute(nums, i + 1, res);//交换之后,也应交换回来,保证后面的递归过程不乱序//比如:26行数据交换之前: 0 ~ i-1 : 123 ;     i~末尾: 456//26行交换之后: 0 ~ i-1 : 123 ;              i~末尾: 546 //然后要将刚才交换的数据,重新交换回来:546 -》 456//然后才去交换 4 和 6 这两个数据;  也就是  有无后效性的问题swap(nums, i, j); }
}private void swap(int[] nums, int left, int right) {int tmp = nums[left];nums[left] = nums[right];nums[right] = tmp;
}

三、有重复值的全排列

LeetCode链接

这道题和上一道题,本质上是一样的,只是这道题可能会出现重复值,我们需要过滤掉这些重复。

解法一:我们还是像上道题一样,生成所有的全排列数据,然后进行用一个方法,进行过滤到重复的数据。此方法是可以的,就是空间和时间有点浪费了。所以我们这里引出一个概念:分支限界

分支限界

解法二:意思就是说,当在同一个位置的时候,有两个同样的数据,都能够来到这个位置,此时我们只需执行一个这样的数据,另外一个同样的数据,我们就不执行(避免)它;听着可能有点糊涂,来看图片吧!

所以,我们只需在第二道题的代码基础之上,加一个机制,用于判断数值曾经来没来过这个位置,就能筛选出所有的重复的全排列。

public List<List<Integer>> permute(int[] nums) {if (nums == null) {return null;}List<List<Integer>> res = new ArrayList<>();getFullPermute(nums, 0, res); //递归调用子过程return res;
}//nums, 是所有的数据。
//nums[0 ... i - 1] 范围内,是已经确定好的数据
//nums[i...] 范围上的数据,就是上图中,绿色框里面剩下的数据,还是待选择的状态
//res,就是最后的结果
private void getFullPermute(int[] nums, int i, List<List<Integer>> res) {if (i == nums.length) {ArrayList<Integer> tmp = new ArrayList<>();for (int data : nums) {tmp.add(data);}res.add(tmp);return;}HashSet<Integer> visited = new HashSet<>(); //用于存储数值,来没来过这个位置//循环遍历剩下的数据for (int j = i; j < nums.length; j++) {if(!visited.contains(nums[j])) {visited.add(nums[j]); //添加已经来过这个位置的数据swap(nums, i, j); //在剩下的数据中,选取一个,放到当前i位置,然后去做递归getFullPermute(nums, i + 1, res);//交换之后,也应交换回来,保证后面的递归过程不乱序//比如:26行数据交换之前: 0 ~ i-1 : 123 ;     i~末尾: 456//26行交换之后: 0 ~ i-1 : 123 ;              i~末尾: 546 //然后要将刚才交换的数据,重新交换回来:546 -》 456//然后才去交换 4 和 6 这两个数据;  也就是  有无后效性的问题swap(nums, i, j);} }
}private void swap(int[] nums, int left, int right) {int tmp = nums[left];nums[left] = nums[right];nums[right] = tmp;
}

好啦,本期更新,就到此结束啦!各位同学,我们下期见!!!

你真的分清楚子序列和全排列了吗?【建议收藏】相关推荐

  1. 华为三层交换机命令集合,已经分好类了,网工建议收藏!

    你好,这里是网络技术联盟站. 本文给大家带来的是华为三层交换机的命令集合,我已经分好类,大家可以收藏备用! 一.系统管理命令 1.1 查看版本信息 display version 此命令用于查看交换机 ...

  2. 越界侦测和区域入侵侦测,你真的分清楚了么?

    越界侦测?区域入侵?你真的分的清吗?今天就给大家详细讲解一下越界侦测和区域入侵两个侦测功能的不同之处以及设置方法. 越界侦测VS区域入侵 通过上面的对比,我们能看出,越界侦测侦测的是画面是否有物体&q ...

  3. 520这一天给你new一个迪丽热巴,可是输出凤姐。你真的分的清new的对象是谁吗?

    前言 一年一度的520又来了,有女朋友的程序员又来杀狗了.但是不要怕,这几天我每天来给你们new几个女朋友 正文 但是,女盆友也不是白给的,需要你自己答出来哦. girlFriend girlFrie ...

  4. 【死磕NIO】— 阻塞IO,非阻塞IO,IO复用,信号驱动IO,异步IO,这你真的分的清楚吗?

    通过上篇文章([死磕NIO]- 阻塞.非阻塞.同步.异步,傻傻分不清楚),我想你应该能够区分了什么是阻塞.非阻塞.异步.非异步了,这篇文章我们来彻底弄清楚什么是阻塞IO,非阻塞IO,IO复用,信号驱动 ...

  5. 6-4 链表拼接 (20分)_青岛喷绘制作公司不愿透露的喷绘布拼接与安装技巧,建议收藏...

    当我们走在大街上随时都能看到各种精美的大型户外喷绘广告,精美的画面很具有吸引力. 青岛喷绘制作公司 0532-80796756 那么大的画面,而设备是有限的,通常大型点设备最宽是5米的,其它3米多为主 ...

  6. 华硕h81m一k跳线图_股票入门基础知识:你真的看懂了K线图了?【建议收藏】1...

    导言--就技术分析而言,我们应该牢记这样得一个原则:事物的后续发展常常和他们之前的表象不一致.我们自以为了解很多事实并不是事实,一些看起来显而易见的事情,有时并不是如此. 最近很多人,说,好像股市最近 ...

  7. qoq是什么意思的缩写_买鞋多年分不清PE、SE、TD什么意思?建议收藏,这些缩写一定要知道...

    一直有在线上线下陪跑抽签买鞋的朋友,可能会经常遇到一些球鞋名字后面带几个字母,但是你真的知道所有英文缩写的意思吗?来看看你都知道哪些单词,建议先收藏再看! WMNS:代表了女款的意思,尺码多为35-4 ...

  8. 初中计算机科目三必背,科目三实用十句口诀,临考提分必背!建议收藏

    如果你已经通过科目二,恭喜你,科三对你来说已经没什么比较难的操作了.只要注意细节,一鼓作气考过的问题不大.元贝驾考学姐为大家将科三最关键的10个操作编成口诀,考前背熟,考试不忘,一把通关! 上车准备做 ...

  9. 定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!

    前言: 你知道计算机内部是如何进行加减运算的吗?可能你知道,那你知道计算机内部是如何进行乘除法运算的呢?肯定和我们十进制运算是不一样的.当我查找资料的时候,发现除了书本很少有这样的知识点.所以我想和大 ...

最新文章

  1. 我的angularjs源码学习之旅2——依赖注入
  2. 新手谈谈网站交互设计
  3. C#操作MySQL数据库的简单例子
  4. CONVERT_YEAR_WITH_THRESHOLD
  5. android9系统webview崩溃,Android WebView已开始在Android 9上崩溃
  6. org.hibernate.HibernateException: No Session found for current thread
  7. MonkeyFest2018 微软最有价值专家讲座
  8. 《走遍中国》珍藏版(十四)
  9. SDOI2014 旅行
  10. python骨灰技巧_Pandas技巧,某骨灰级Pythoner经验总结,呕心沥血!
  11. Dockter:研究人员的容器图像生成器
  12. STM8S——watchdog(IWDG)
  13. 网络邻居无法查找计算机,局域网中无法找到网上邻居的原因
  14. FBReader集成后,打开书出现空白页面
  15. Dicom影像查看器
  16. 金蝶二次开发 的新手体会
  17. VC++ 绘制线条 OnLButtonDown函数(DrawView.cpp) 利用SDK全局函数实现画线功能 利用MFC的CDC类实现画线功能 利用MFC的CClientDC类实现画线功能
  18. 英雄联盟手游注册及下载教程(ios及安卓android最新最全版)
  19. 端午临中夏,时清日复长。
  20. 【调剂】中国航空研究院631所2022年调剂信息

热门文章

  1. 如何在Xcode里面运行C语言程序---简单展示
  2. 私有化部署ChatGPT道路上的各种坑
  3. 【电子书+代码】Sklearn,Keras与Tensorflow机器学习实用指南
  4. modis数据简介及批处理工具
  5. ROS入门学习笔记|话题发布与订阅
  6. C++探索之旅 | 第一部分第一课:什么是C++
  7. Windows2008开启telnet命令的方法
  8. 单枪匹马年赚一个亿?靠的是任务管理做得漂亮!
  9. cannot bind non-const lvalue reference of type ‘xxx‘ to an rvalue of type ‘xxx‘
  10. SNMP Trap的session问题