问题

剑指 Offer 38. 字符串的排列
难度:中等
输入一个字符串,打印出该字符串中字符的所有排列。

你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。

示例:
输入:s = “abc”
输出:[“abc”,”acb”,”bac”,”bca”,”cab”,”cba”]

限制:
1 <= s 的长度 <= 8

解答

排列的数量:对一个长度为 n 的字符串(字符不重复),排列的总数量为 : n (n-1) (n-2) … *1,全排列
算法的思路:

  • 利用深度遍历算法,通过字符交换,依次固定第一位(有 n 种情况),第二位(有 n - 1 种情况),…,第 n 位(只有一种情况);
  • 出现重复的字符,利用 Set 去重,当字符出现 set 中,说明匹配过了, 跳过此字符。

深度遍历的流程:
递归结束条件:当 n 到达最后一个位置,也就是 n = s.length() - 1,说明已经固定到最后一位,最后一位的情况只有一种,所以直接将排列后的字符数组生成字符串,添加到 res 中。

递归的工作: 初始化一个 Set 集合,用于去除重复固定过的字符,for 循环将 i 与 [n, s.length()] 区间位置的字符交换,固定第 n 个位置的字符,递归调用 dfs(n+1) 固定下一个位置的字符,递归返回时,再将交换的字符还原。

  1. class Solution {
  2. char[] arrangement = null;
  3. List<String> res = null;
  4. int len;
  5. public String[] permutation(String s) {
  6. res = new ArrayList<>();
  7. arrangement = s.toCharArray();
  8. len = s.length();
  9. arrange(0);
  10. return res.toArray(new String[res.size()]);
  11. }
  12. // 深度遍历,依次固定第 n 个位置的字符
  13. private void dfs(int n){
  14. if(k == len - 1){
  15. res.add(new String(arrangement));
  16. return;
  17. }
  18. Set<Character> set = new HashSet<>();
  19. // 逐个交换,回溯时还原。
  20. for(int i = n; i < len; i++){
  21. if(set.contains(arrangement[i]))
  22. continue;
  23. set.add(arrangement[i]);
  24. char t = arrangement[n];
  25. arrangement[n] = arrangement[i];
  26. arrangement[i] = t;
  27. dfs(n+1);
  28. arrangement[i] = arrangement[n];
  29. arrangement[n] = t;
  30. }
  31. }
  32. }

执行结果:通过
显示详情
执行用时:9 ms, 在所有 Java 提交中击败了97.92%的用户
内存消耗:44 MB, 在所有 Java 提交中击败了100.00%的用户

数据结构用错版本,导致运行时间翻倍
原因:排列的时候已经去重了,添加结果的时候就不需要去重了,

  1. class Solution {
  2. public String[] permutation(String s) {
  3. Set<String> res = new HashSet<>(); // 该位置换成 List
  4. recur(s.toCharArray(), 0, res);
  5. return res.toArray(new String[res.size()]);
  6. }
  7. private void recur(char[] s, int index ,Set<String> res){
  8. if(index >= s.length -1 ){
  9. res.add(String.valueOf(s));
  10. return;
  11. }
  12. Set<Character> mark = new HashSet<>();
  13. for (int i = index; i < s.length; i ++){
  14. if(mark.contains(s[i]))
  15. continue;
  16. mark.add(s[i]);
  17. swap(s, i, index);
  18. recur(s, index+1, res);
  19. swap(s, index, i);
  20. }
  21. }
  22. private void swap(char[] s, int i, int j){
  23. char temp = s[i];
  24. s[i] = s[j];
  25. s[j] = temp;
  26. }
  27. }