38. 字符串的排列
文章目录
- 剑指 Offer 38. 字符串的排列
- 解题思路
- Java代码
- 扩展题一:LeetCode 46. 全排列
- 解题思路
- Java代码
- 扩展题二:LeetCode 47. 全排列 II
- 解题思路
- Java代码
剑指 Offer 38. 字符串的排列
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
输入: s = “abc”
输出: [“abc”,“acb”,“bac”,“bca”,“cab”,“cba”]
限制:
1 <= s 的长度 <= 8
解题思路
深度优先遍历和去重技巧的结合。
根据字符串排列的特点,考虑深度优先搜索所有排列方案。即通过字符摆放,先固定第 1
位字符( n
种情况)、再固定第 2
位字符(n-1
种情况)、… 、最后固定第n
位字符( 1
种情况)。
说的通俗一点就是把n
个数字放到n
个框里,有多少种放法,对于每个框,我们都有n
个数字,即n
个选择,但我们要判断手中的数字是否已经放入其他框了,故需要用到一个标记数组
。
上图是没有重复字符的情况,如果出现了重复字符怎么办,这就涉及到去重
了,有重复字符的情况如下图。
我们会发现abb’
与ab’b
,bab'
与b’ab
,bb'a
与b’ba
是重复的,为什么会出现这种情况?
我们可以先回忆一下初中就学过的掷骰子,掷两个骰子,出现(4,2)
和(2,4)
是视为两种不同的情况的,但是出现(3,3)
和(3,3)
则只视为一种情况,因为“第一个骰子点数是3
,第二个骰子点数也是3
”与“第二个骰子点数是3
,第一个骰子点数也是3
”是完全相同的结果。
引申到排列中,为了举例方便,这里用数字11'2345
- 第一个框放
1
,然后让1'2345
五个数字全排列放在其余位置 - 第一个框放
1'
,然后让12345
五个数字全排列放在其余位置
不难发现,情况一和二得到的排列结果将一模一样。道理和掷骰子一样,不管是把1
还是1'
放第一个框,它们终归都是1
,然后后面的框放的也同样都是12345
的全排列,那么最终产生的所有排列结果的集合肯定是一样的。
由此为了去重,我们可以定义一个规则,即对于相同数,我们人为定序,如上例子中11'2345
,我们指定重复数字首次要放入某一个框位
时,只能放重复数字的第一个,如这里只能放1
,放1'
的情况直接过滤,其他框位同理。
Java代码
class Solution {private String[] res;//最开始并不知道res最终的长度会是多少,故先把排列结果都放到list中//之后转到res中即可private List<String> list = new ArrayList<>();public String[] permutation(String s) {if(s == null || s.length() == 0) return new String[0];boolean[] isVisited = new boolean[s.length()];//由于要去重,故得先排序,因此将String转为char数组再排序char[] chs = s.toCharArray();Arrays.sort(chs);dfs(chs,new StringBuilder(),isVisited);//将结果放到数组中,因为返回结果需要的是String数组res = new String[list.size()];for(int i = 0;i < list.size();i++){res[i] = list.get(i);}return res;}public void dfs(char[] chs,StringBuilder sb,boolean[] isVisited){if(sb.length() == chs.length){list.add(new StringBuilder(sb.toString()).toString());return ;}for(int i = 0;i < chs.length;i++){//全排列算法去重条件模板//如果这个字符和前一个字符相同且前一个字符还没有用过,continue//即我们规定重复字符首次要放入某一个框位时,只能放重复字符的第一个//比如a,a',b是可以的,但是a',a,b和其重复,应该去重,故当要达到产生a',a,b那一层递归栈时//由于a'与前一个字符a相同,且a还没有用过,所以continue,这刚好去重,是我们想要的结果if(i > 0 && chs[i] == chs[i - 1] && !isVisited[i - 1]) continue;if(!isVisited[i]){sb.append(chs[i]);isVisited[i] = true;dfs(chs,sb,isVisited);//恢复现场sb.deleteCharAt(sb.length() - 1);isVisited[i] = false;}}}
}
这里的去重对于刚接触的同学来说确实不太好理解(我刚开始学的时候也绕了一天,绕明白后就感觉是常识了。。。),为了更好的理解,下面来两道扩展题,尤其是第二道题,实在没想明白去重时,可以跟着第二题的代码模拟一下代码执行过程,说不定突然理解了,我当时貌似就是这样绕过来的。
扩展题一:LeetCode 46. 全排列
给定一个 没有重复
数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
解题思路
深度优先
即可,可以理解成把n
个数字放到n
个框里,有多少种放法,对于每个框,我们都有n
个数字,即n
个选择,但我们要判断手中的数字是否已经放入其他框了,故用到一个标记数组。
Java代码
class Solution {public List<List<Integer>> permute(int[] nums) {List<List<Integer>> res = new ArrayList<>();if(nums == null) return res;boolean[] isVisited = new boolean[nums.length];dfs(res,new ArrayList<>(),nums,isVisited);return res;}private void dfs(List<List<Integer>> res,List<Integer> list,int[] nums,boolean[] isVisited){//总共就nums.length个框,当list.size() = nums.length时,说明手中数字都放完了if(list.size() == nums.length){res.add(new ArrayList<>(list));//添加的是list副本return;}for(int i = 0;i<nums.length;i++){if(!isVisited[i]){list.add(nums[i]);isVisited[i] = true;dfs(res,list,nums,isVisited);//回溯时,将list,isVisited还原为上一级栈的状态list.remove(list.size()-1);isVisited[i] = false;}} }
}
扩展题二:LeetCode 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
解题思路
与上题一样,但多个去重
,去重方式看代码注释处
,注意这里去重得先排序
(我之前自己有时也忘记了,然后在那里检查哪里出了错,0.0)。
Java代码
class Solution {public List<List<Integer>> permuteUnique(int[] nums) {List<List<Integer>> res = new ArrayList<>();if(nums == null) return res;Arrays.sort(nums);//要去重,故先排序boolean[] isVisited = new boolean[nums.length];dfs(res,new ArrayList<>(),nums,isVisited);return res;}private void dfs(List<List<Integer>> res,List<Integer> list,int[] nums,boolean[] isVisited){//总共就nums.length个框,当list.size() = nums.length时,说明手中数字都排完了if(list.size() == nums.length){res.add(new ArrayList<>(list));//添加的是list副本return;}for(int i = 0;i<nums.length;i++){//如果这个数和前一个数相同且前一个数还没有用过,continue//即我们规定重复数字首次要放入某一个框位时,只能放重复数字的第一个//比如1,1',2是可以的,但是1',1,2和其重复,应该去重,故当要达到产生1',1,2那一层递归栈时//由于1'与前一个数1相同,且1还没有用过,所以continue,这刚好去重,是我们想要的结果if(i>0 && nums[i] == nums[i-1] && !isVisited[i-1]) continue;if(!isVisited[i]){list.add(nums[i]);isVisited[i] = true;dfs(res,list,nums,isVisited);//回溯时,将list,isVisited还原为上一级栈的状态list.remove(list.size()-1);isVisited[i] = false;}} }
}
38. 字符串的排列相关推荐
- 剑指offer:面试题38. 字符串的排列
题目:面试题38. 字符串的排列 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" 输 ...
- 【LeetCode】剑指 Offer 38. 字符串的排列
[LeetCode]剑指 Offer 38. 字符串的排列 文章目录 [LeetCode]剑指 Offer 38. 字符串的排列 package offer;import java.util.Hash ...
- ++递归 字符串全排列_剑指 Offer 38. 字符串的排列
剑指 Offer 38. 字符串的排列 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" ...
- 剑指Offer系列(java版,详细解析)38.字符串的排列
题目描述 剑指 Offer 38. 字符串的排列 难度中等237收藏分享切换为英文接收动态反馈 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元 ...
- LeetCode——剑指 Offer 38. 字符串的排列
剑指 Offer 38. 字符串的排列 题目 输入一个字符串,打印出该字符串中字符的所有排列.你可以以任意顺序返回这个字符串数组,但里面不能有重复元素.示例:输入:s = "abc" ...
- [230516 剑指38] 字符串的排列
[230516 剑指38] 字符串的排列 一 题目 剑指 Offer 38. 字符串的排列 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. ...
- 剑指 Offer 38. 字符串的排列
import java.util.ArrayList; import java.util.HashSet; import java.util.List;/*** 剑指 Offer 38. 字符串的排列 ...
- 【击败时间100%】剑指 Offer 38. 字符串的排列
立志用最少的代码做最高效的表达 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" 输出 ...
- 剑指Offer - 面试题38. 字符串的排列(全排列,排序,回溯+剪枝)
1. 题目 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" 输出:["ab ...
最新文章
- 执行eclipse,迅速failed to create the java virtual machine。
- python盘点订单_django解决订单并发问题【推荐】
- 在线CSS工具及相关资源收集
- 线程返回值的方式介绍
- Goland实现Set操作
- 解决远程登录MYSQL数据库
- 初学__Python——Python中文支持、Python计算器
- 汇编语言等号=伪指令
- 使用Jmeter压力测试工具测试
- 130242014018-郑志良-第2次实验
- 程序员,当你写程序写累了怎么办。
- 幼儿园计算机教师论文,幼儿园中班教师论文
- 【Flink】Flink 周期性 watermark 的 传播 AssignerWithPeriodicWatermarks
- linux安装协议,在Linux中安装IPv6协议
- anaconda安装python包_Anaconda:安装或更新 Python 第三方包
- Python标准库中的glob
- Labelling tools 的环境配置
- 叉乘点乘混合运算公式_【“数”你好看】对数运算(Logarithm)
- 微信小程序开发手账从入门到部署【持续更新】
- int类型与char类型
热门文章
- 电阻、电容及电感的高频等效电路及特性曲线
- java 圆类 圆锥类_喉室位于_java程序设计答案_学小易找答案
- 【Kafka】Kafka的安装
- 单片机音乐盒c语言源程序,51单片机八音盒源程序(汇编语言)
- java web 找回密码_java web实现 忘记密码(找回密码)功能及代码
- abl如何调用xbl里面的protocol
- 研究发现:“帽子”越多越高的教师,对研究生越没有用
- python如何截长图_selenium定时爬取长截图
- 如何批量重命名文件夹,自定义修改文件夹的名称
- NRF51822蓝牙服务(9)——动态修改设备的名称