文章目录

  • 剑指 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’bbab'b’abbb'ab’ba是重复的,为什么会出现这种情况?

我们可以先回忆一下初中就学过的掷骰子,掷两个骰子,出现(4,2)(2,4)是视为两种不同的情况的,但是出现(3,3)(3,3)则只视为一种情况,因为“第一个骰子点数是3,第二个骰子点数也是3”与“第二个骰子点数是3,第一个骰子点数也是3”是完全相同的结果。

引申到排列中,为了举例方便,这里用数字11'2345

  1. 第一个框放1,然后让1'2345五个数字全排列放在其余位置
  2. 第一个框放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. 字符串的排列相关推荐

  1. 剑指offer:面试题38. 字符串的排列

    题目:面试题38. 字符串的排列 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" 输 ...

  2. 【LeetCode】剑指 Offer 38. 字符串的排列

    [LeetCode]剑指 Offer 38. 字符串的排列 文章目录 [LeetCode]剑指 Offer 38. 字符串的排列 package offer;import java.util.Hash ...

  3. ++递归 字符串全排列_剑指 Offer 38. 字符串的排列

    剑指 Offer 38. 字符串的排列 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" ...

  4. 剑指Offer系列(java版,详细解析)38.字符串的排列

    题目描述 剑指 Offer 38. 字符串的排列 难度中等237收藏分享切换为英文接收动态反馈 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元 ...

  5. LeetCode——剑指 Offer 38. 字符串的排列

    剑指 Offer 38. 字符串的排列 题目 输入一个字符串,打印出该字符串中字符的所有排列.你可以以任意顺序返回这个字符串数组,但里面不能有重复元素.示例:输入:s = "abc" ...

  6. [230516 剑指38] 字符串的排列

    [230516 剑指38] 字符串的排列 一 题目 剑指 Offer 38. 字符串的排列 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. ...

  7. 剑指 Offer 38. 字符串的排列

    import java.util.ArrayList; import java.util.HashSet; import java.util.List;/*** 剑指 Offer 38. 字符串的排列 ...

  8. 【击败时间100%】剑指 Offer 38. 字符串的排列

    立志用最少的代码做最高效的表达 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" 输出 ...

  9. 剑指Offer - 面试题38. 字符串的排列(全排列,排序,回溯+剪枝)

    1. 题目 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" 输出:["ab ...

最新文章

  1. 执行eclipse,迅速failed to create the java virtual machine。
  2. python盘点订单_django解决订单并发问题【推荐】
  3. 在线CSS工具及相关资源收集
  4. 线程返回值的方式介绍
  5. Goland实现Set操作
  6. 解决远程登录MYSQL数据库
  7. 初学__Python——Python中文支持、Python计算器
  8. 汇编语言等号=伪指令
  9. 使用Jmeter压力测试工具测试
  10. 130242014018-郑志良-第2次实验
  11. 程序员,当你写程序写累了怎么办。
  12. 幼儿园计算机教师论文,幼儿园中班教师论文
  13. 【Flink】Flink 周期性 watermark 的 传播 AssignerWithPeriodicWatermarks
  14. linux安装协议,在Linux中安装IPv6协议
  15. anaconda安装python包_Anaconda:安装或更新 Python 第三方包
  16. Python标准库中的glob
  17. Labelling tools 的环境配置
  18. 叉乘点乘混合运算公式_【“数”你好看】对数运算(Logarithm)
  19. 微信小程序开发手账从入门到部署【持续更新】
  20. int类型与char类型

热门文章

  1. 电阻、电容及电感的高频等效电路及特性曲线
  2. java 圆类 圆锥类_喉室位于_java程序设计答案_学小易找答案
  3. 【Kafka】Kafka的安装
  4. 单片机音乐盒c语言源程序,51单片机八音盒源程序(汇编语言)
  5. java web 找回密码_java web实现 忘记密码(找回密码)功能及代码
  6. abl如何调用xbl里面的protocol
  7. 研究发现:“帽子”越多越高的教师,对研究生越没有用
  8. python如何截长图_selenium定时爬取长截图
  9. 如何批量重命名文件夹,自定义修改文件夹的名称
  10. NRF51822蓝牙服务(9)——动态修改设备的名称