leetcode
leetcode 2801 ~ 2850
无重复字符串的排列组合

无重复字符串的排列组合

难度:

标签:

题目描述

Write a method to compute all permutations of a string of unique characters.

Example1:

 Input: S = "qwe"
 Output: ["qwe", "qew", "wqe", "weq", "ewq", "eqw"]

Example2:

 Input: S = "ab"
 Output: ["ab", "ba"]

Note:

  1. All charaters are English letters.
  2. 1 <= S.length <= 9

代码结果

运行时间: 43 ms, 内存: 21.7 MB


/*
 * 思路:
 * 使用Java Stream API和递归来生成字符串的所有排列组合。将字符串拆分成字符数组,
 * 然后通过流操作递归地生成所有排列。
 */
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class StreamPermutations {
    public static List<String> getPermutations(String S) {
        if (S.isEmpty()) {
            return List.of("");
        }
        return IntStream.range(0, S.length())
                .mapToObj(i -> {
                    String remaining = S.substring(0, i) + S.substring(i + 1);
                    return getPermutations(remaining).stream()
                            .map(p -> S.charAt(i) + p)
                            .collect(Collectors.toList());
                })
                .flatMap(List::stream)
                .collect(Collectors.toList());
    }

    public static void main(String[] args) {
        System.out.println(getPermutations("qwe")); // [qwe, qew, wqe, weq, ewq, eqw]
    }
}

解释

方法:

这个题解使用了回溯算法来生成字符串的所有排列。首先,将字符串转化为字符列表,然后通过递归的深度优先搜索(DFS)方法,通过不断交换字符位置来探索所有可能的排列。具体而言,对于每个递归层,算法通过遍历从当前位置到字符串末尾的所有字符,并与当前位置的字符进行交换,来生成新的排列。交换后,算法递归到下一个位置,继续进行字符交换直到到达字符串的末尾,此时记录一个完整的排列。随后,通过回溯(即再次交换字符)恢复原字符串的顺序,以便进行后续的排列生成。

时间复杂度:

O(n*n!)

空间复杂度:

O(n)

代码细节讲解

🦆
在递归方法`dfs`中,为什么要在递归到字符串最后一个字符时直接将排列结果添加到结果列表中,而不是继续交换?
在递归方法`dfs`中,当递归到字符串的最后一个字符时,意味着当前的字符组合已经形成了一个完整的排列,因为从字符串的第一个字符到最后一个字符的每个位置都固定了字符。此时,没有必要继续交换,因为已经达到了字符串的末尾,不存在更多的字符可以进行交换。直接将这个完整的排列添加到结果列表是合理的,因为这代表了一种独特的字符排列。
🦆
回溯算法中的交换步骤`s[i], s[x] = s[x], s[i]`进行了两次,请解释为什么需要在递归调用后再次交换回来?
在回溯算法中,第一次交换`s[i], s[x] = s[x], s[i]`是为了将当前索引`x`的元素与循环中的索引`i`的元素交换,这样可以形成新的字符排列进入下一层递归。递归调用`dfs(x+1)`后,需要再次执行交换`s[i], s[x] = s[x], s[i]`,目的是恢复字符串到递归之前的状态。这样回溯到上一层递归时,字符串的顺序是未被改变的,确保每次递归都是从原始(或上一状态的)字符串开始,以探索所有可能的字符排列。这种方法确保了算法正确性和完整性,每次递归都能基于一个未被修改的字符序列进行。
🦆
如何保证生成的排列中不会有重复,尽管字符串中的字符都是独一无二的?
由于题目已经明确指出字符串中的每个字符都是独一无二的,因此在使用回溯算法生成排列时,每次交换都会产生一个新的字符组合。由于每个字符只使用一次,并且每种组合都是通过交换不同位置的字符得到的,因此不可能重复生成相同的排列。再加上回溯算法通过递归和回溯确保探索了所有可能的排列方式,所以在这种情况下不需要额外的机制来防止排列的重复。每个排列都是唯一生成的,确保了输出的排列列表中不会有重复。

相关问题