剑指 Offer 38. 字符串的排列(回溯法)


题目

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

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

示例:

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

限制:

1 <= s 的长度 <= 8

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


一、解题思路

在阐述思路前,我们先来看看回溯法。

解决一个回溯问题,实际上就是一个决策树的遍历过程。

你只需要思考三个问题:

  1. 路径
  2. 选择
  3. 结束条件

代码方面有一个模板:

	res[];
	public void dfs(参数){
        if(满足条件){
            res.add();
        }
        for(遍历选择列表){
            做选择
            dfs(参数)
            撤销选择
        }
    }

核心就是for循环里的递归,递归前选择,递归后撤销
在这里插入图片描述
我们不妨称这为回溯法的决策树,因为每个节点都在做决策。
而回溯呢,就是在你决策之后回溯到决策前的状态,上面就是回溯法的大体理解。


回到这个题目来,我们先认为传入进来的字符串是不重复的。

字符串转char数组 char[] c:[a,b,c].

我们可以先固定第一位字符(n种情况),再固定第二位字符(n-1种情况),最后再固定第n个字符(1种情况)。

例如在固定第x位字符时,我们可以通过遍历数组
for(int i=x;i<c.length;i++) -----x为当前需要固定的字符的下标
依次令c[i]与c[x]交换,从而实现固定的第一位字符有n种情况

当然在固定好第一位字符后,会依次固定第二位,第三位,,第n位。。
只有第n位固定好后,才会回溯到决策前的状态,也就是固定第n-1位。
(上面有点绕,简单点说回溯法是会向下递归到最后才会开始向上回溯)

刚刚我们讨论了字符串不重复的情况,而在字符串有重复字符的时候,我们就得进行剪枝操作

例如字符串 “abb”
如果不进行剪枝,那么结果就会出现重复的 abb,bba,bab.
我们可以用hash表的contians()方法进行判断当前固定的字符之前是否已经固定过了。

递归解析:

  1. 结束条件:x=c.length-1时,当前可以选择的字符只有一个,所以直接将当前数组c加入到res。
  2. 递推参数:当前需要固定位x
  3. 递推工作: 初始化一个 Set ,用于排除重复的字符;将第 x 位字符与 i ∈ [x, len(c) ] 字符分别交换,并进入下层递归;
  4. 剪枝: 若 c[i] 在 Set​ 中,代表其是重复字符,因此 “剪枝” ;将 c[i] 加入 Set​ ,以便之后遇到重复字符时剪枝;
  5. 固定字符: 将字符 c[i] 和 c[x] 交换,即固定 c[i] 为当前位字符;
  6. 开启下层递归: 调用 dfs(x + 1) ,即开始固定第 x + 1 个字符;
  7. 还原交换: 将字符 c[i] 和 c[x] 交换(还原之前的交换);

二、代码

class Solution {
    List<String> res = new LinkedList<>();
    char[] c;
    public String[] permutation(String s) {
        c = s.toCharArray();
        dfs(0);
        return res.toArray(new String[res.size()]);
    }
    public void dfs(int x){
        if(x==c.length-1){
            res.add(String.valueOf(c));
        }
        HashSet<Character> set = new HashSet<>();
        for(int i=x;i<c.length;i++){
            if(set.contains(c[i])) continue;
            set.add(c[i]);
            swap(x,i);
            dfs(x+1);
            swap(x,i);
        }
    }
    public void swap(int a,int b){
        char temp =c[a];
        c[a]=c[b];
        c[b]=temp;
    }

}

回溯算法详解参考
https://mp.weixin.qq.com/s/nMUHqvwzG2LmWA9jMIHwQQ
解析参考力扣用户Krahets
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/

侵删

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值