剑指 Offer 38. 字符串的排列---回溯+剪枝

剑指 Offer 38. 字符串的排列

输入一个字符串,打印出该字符串中字符的所有排列。

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

示例:

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

输入一个字符串,打印出该字符串中字符的所有排列。

来源:力扣(LeetCode)
链接:点击跳转题目https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof


题目思路

排列方案的生成:
根据字符串排列的特点,考虑深度优先搜索所有排列方案。即通过字符交换,先固定第 1 位字符( n 种情况)、再固定第 2 位字符( n−1 种情况)、… 、最后固定第 nn 位字符( 1 种情况)。
剑指 Offer 38. 字符串的排列---回溯+剪枝_第1张图片

重复排列方案与剪枝:
当字符串存在重复字符时,排列方案中也存在重复的排列方案。为排除重复方案,需在固定某位字符时,保证 “每种字符只在此位固定一次” ,即遇到重复字符时不交换,直接跳过。从 DFS 角度看,此操作称为 “剪枝” 。
剑指 Offer 38. 字符串的排列---回溯+剪枝_第2张图片
递归解析:

  1. 终止条件: 当 x = len(arr) - 1 时,代表所有位已固定(最后一位只有 11种情况),则将当前组合 arr 转化为字符串并加入 res ,并返回;
  2. 递推参数: 当前固定位 x ;
  3. 递推工作: 初始化一个 Set ,用于排除重复的字符;将第 x 位字符与 i ∈ [x, len©] 字符分别交换,并进入下层递归;
    (1)剪枝: 若 c[i] 在 Set​ 中,代表其是重复字符,因此 “剪枝” ;
    (2)将 c[i] 加入 Set​ ,以便之后遇到重复字符时剪枝;
    (3)固定字符: 将字符 c[i] 和 c[x] 交换,即固定 c[i] 为当前位字符;
    (4)开启下层递归: 调用 dfs(x + 1) ,即开始固定第 x + 1 个字符;
    (5)还原交换: 将字符 c[i] 和 c[x] 交换(还原之前的交换);

作者:jyd
链接:https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof/solution/mian-shi-ti-38-zi-fu-chuan-de-pai-lie-hui-su-fa-by/
来源:力扣(LeetCode)

代码注释解析

public class Solution {

    List<String> list = new ArrayList();    //链表存放每次构建的字符串
    public char[] arr;

    public String[] permutation(String s) {
        arr = s.toCharArray();  //把字符串s的所有字符存放在数组arr中
        dfs(0); //从第0层开始递归
        return list.toArray(new String[list.size()]);   //把顺序表中存的字符串变为为数组字符串输出
    }

    //递归函数,x为arr数组下标
    public void dfs(int x) {
        //当x走到倒数第二个元素时,说明前面所有元素固定完了,剩下一个不用固定
        if(x == arr.length-1) {
            list.add(new String(arr));  //此时把该顺序的数组转为字符串加入到顺序表中
            return; //递归结束,返回上一层
        }
        //需要一个set来存放已经遍历过的元素
        Set<Character> set = new HashSet<>();
        //遍历每一层,每次从x开始遍历
        for(int i = x; i < arr.length; i++) {
            //发生剪枝,当包含这个元素的时候,直接跳过
            if(set.contains(arr[i])) {
                continue;
            }
            set.add(arr[i]);    //程序走到这说明没有剪枝,那么把该元素放到set中
            swap(x,i);  //交换元素,将arr[i]固定在第 x 位
            dfs(x+1);   //进入下一层递归,开启固定第 x + 1 位字符
            swap(x,i);  // 恢复交换
        }
    }

    //数组中元素交换
    public void swap(int i, int j) {
        char tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

}

你可能感兴趣的:(刷题,字符串,剪枝,数据结构,java,dfs)