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

有重复字符串的排列组合

难度:

标签:

题目描述

Write a method to compute all permutations of a string whose characters are not necessarily unique. The list of permutations should not have duplicates.

Example1:

 Input: S = "qqe"
 Output: ["eqq","qeq","qqe"]

Example2:

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

Note:

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

代码结果

运行时间: 22 ms, 内存: 16.0 MB


/*
 * 思路:
 * 1. 使用递归生成字符串的所有排列。
 * 2. 利用Java Stream API处理结果集合和转换操作。
 */
import java.util.*;
import java.util.stream.Collectors;

public class PermutationStream {
    public List<String> permutation(String S) {
        Set<String> result = new HashSet<>();
        permute(S.toCharArray(), 0, result);
        return result.stream().collect(Collectors.toList());
    }

    private void permute(char[] chars, int index, Set<String> result) {
        if (index == chars.length) {
            result.add(new String(chars));
            return;
        }
        for (int i = index; i < chars.length; i++) {
            swap(chars, index, i);
            permute(chars, index + 1, result);
            swap(chars, index, i); // 回溯
        }
    }

    private void swap(char[] chars, int i, int j) {
        char temp = chars[i];
        chars[i] = chars[j];
        chars[j] = temp;
    }

    public static void main(String[] args) {
        PermutationStream solution = new PermutationStream();
        System.out.println(solution.permutation("qqe"));
        System.out.println(solution.permutation("ab"));
    }
}

解释

方法:

此题解采用了递归回溯的方法来生成字符串的所有排列组合。首先,对给定字符串的每一个字符,将其作为当前排列的第一个字符,然后对剩余的字符再进行排列。为了避免重复的排列,通过检查当前字符是否在它前面的字符中出现过来跳过重复的情况。这样可以确保每个字符在每个位置上只被使用一次。每一层递归都会减少一个字符,直到字符串为空,此时返回包含空字符串的数组。

时间复杂度:

O(n * n!)

空间复杂度:

O(n!)

代码细节讲解

🦆
在递归回溯方法中,你是如何确保不会对已经处理过的字符进行重复处理的?
在递归回溯的过程中,通过设置一个判断条件来检查当前字符是否已经在前面被选作排列的一部分。具体来说,在每次选择一个字符作为当前排列的第一个字符时,我会检查这个字符是否在它之前的位置出现过。如果出现过,就跳过这个字符,防止生成重复的排列组合。这种方法确保了每个字符在每个位置只被使用一次,从而有效避免了重复处理相同的字符。
🦆
你提到通过检查当前字符是否在它前面的字符中出现过来跳过重复,这种方法在所有情况下都有效吗,还是有可能遗漏某些重复排列?
这种方法在所有情况下都是有效的,前提是输入的字符串是预先排序的。如果字符串未排序,相同的字符可能分布在字符串的不同位置,导致在不同的递归层级被重复处理。因此,在使用这种策略之前确保字符串是排序的可以避免这种情况。如果字符串已经排序,那么检查当前字符是否已在它之前的位置出现过,可以确保不会生成重复的排列组合,因为每次递归都会处理不包含当前已经选择字符的剩余部分。
🦆
对于字符串中的每一个字符,你选择将其作为当前排列的第一个字符,然后对剩余字符进行排列。这种方法有没有考虑字符的频率或者其他属性来优化性能?
在当前的解决方案中,没有直接考虑字符的频率或其他属性来优化性能。这种基本的递归回溯方法主要侧重于简单地生成所有可能的排列,而不考虑输入字符串中字符的具体属性。然而,可以通过一些优化策略来提高效率,例如使用计数排序或哈希表来记录每个字符的出现次数,然后基于这些统计数据来减少不必要的递归调用。例如,如果某个字符已经用完其出现次数,就不再进行递归。这样的优化可以在保持算法简洁性的同时,减少计算量,特别是对于包含重复字符较多的字符串。

相关问题