import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str string字符串 
     * @return string字符串ArrayList
     */
    public ArrayList<String> Permutation (String str) {
        // write code here
        // 左程云老师讲过全排列的分支限界递归法解决不重复全排列问题
        // 调用一个递归函数,这个递归函数负责对当前i位置的字符进行与i ~ chars.length - 1中的位置依次互换,然后继续考察i + 1处的情况
        // 分支界限法去重:定义一个HashSet,这个位置没有出现过该值才允许进入分支,否则跳过

        // 算法的时间复杂度0(N!),额外空间复杂度0(N!)

        // 用于记录所有路径的结果
        ArrayList<String> finalResults = new ArrayList<>();

        // 调用这个递归函数,从num数组的0位置开始,将每一次找到的oneResult填进finalResult中
        process(str.toCharArray(), finalResults, 0);

        // 返回最终的答案finalResults
        return finalResults;
    }

    public void process(char[] chars, ArrayList<String> finalResults, int i) {
        // 递归出口(底部)
        if (i == chars.length) {
            // i越界了,说明整个数组遍历完毕了,将单个路径上的答案oneResult写入总答案finalResults中
            finalResults.add(String.valueOf(chars));
        }

        // 递归分支
        HashSet<Character> set = new HashSet<>();
        for (int j = i; j < chars.length; j++) {
            if (!set.contains(chars[j])) {
                // 将num[j]登记
                set.add(chars[j]);
                // 假设本位置与j位置的元素交换
                swap(chars, i, j);
                // 在交换完的基础上继续考察num数组中i+1往后的位置该如何排列
                process(chars, finalResults, i + 1);
                // 注意!恢复现场,继续尝试将本位值与num[j + 1]位置的元素交换
                // 踩坑点2:一定要【恢复现场】,要不然无法准确列出要分支的情况
                swap(chars, j, i);
            }
        }
    }

    // 数组元素交换函数
    public void swap(char[] chars, int i, int j) {
        if (i == j) {
            return;
        }
        char t = chars[i];
        chars[i] = chars[j];
        chars[j] = t;
    }
}