【LeetCode】剑指38——字符串的排列(难度:中等)

【LeetCode】剑指38——字符串的排列(难度:中等)

题目描述

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

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

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

限制:1 <= s 的长度 <= 8

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

以一个例子“abcd”来展开说明,我们知道一共有24种排列的方式

  1. 本身abcd是一种
  2. 将后两个字母交换:abdc,然后我们再换回来,回到abcd
  3. 将abcd的b和c交换:acbd
  4. 再将后两个字母交换:acdb,然后我们再换回来,成为acbd。再换回来,回到abcd
  5. 将abcd的b和d交换:adcb
  6. 再将后两个字母交换:adbc,然后我们再换回来,成为adcb。再换回来,回到abcd
  7. 将abcd的a和b交换:bacd
  8. 再将后两个字母交换:badc,然后我们再换回来,成为bacd
  9. 将bacd的a和c交换:bcad
  10. 再将后两个字母交换:bcda,然后我们再换回来,成为bcad。再换回来,成为bacd
  11. 将bacd的a和d交换:bdca
  12. 再将后两个字母交换:bdac。再换回去,成为bdca。再换回来,成为bacd。再换回来,回到abcd
  13. 将abcd的a和c交换:cbad
  14. 再将后两个字母交换:cbda,然后我们再换回来,成为cbad
  15. 将cbad的b和a交换:cabd
  16. 再将后两个字母交换:cadb,然后我们再换回来,成为cabd。再换回来,成为cbad
  17. 将cbad的b和d交换:cdab
  18. 再将后两个字母交换:cdba,然后我们再换回来,成为cdab。再换回来,成为cbad,再换回来,回到abcd
  19. 将abcd的a和d交换:dbca
  20. 再将后两个字母交换:dbac
  21. 将dbca的b和c交换:dcba
  22. 再将后两个字母交换:dcab,然后我们再换回来,成为dcba。再换回来,成为cbca
  23. 将dbca的b和a交换:dacb
  24. 再将后两个字母交换:dabc,然后我们再换回来,成为dacb。再换回来,成为dbca。再换回来回到abcd。

我们发现存在一个回溯的操作,因此这里使用递归+回溯的算法

此外同一个字母可能出现多次,为防止重复,使用Set集合去重

代码详解

class Solution {

    char[] cs; // 将String拆成char[]数组,方便字母交换
    Set<String> set; // 防止字符串重复

    public String[] permutation(String s) {
        cs = s.toCharArray();
        set = new HashSet<>();
        dfs(0, s.length()); // 递归完毕后,set集合里便是全部的答案了
        int index = 0;
        String[] ss = new String[set.size()];
        for(String _s : set) {
            ss[index] = _s;
            ++index;
        }
        return ss;
    }

    public void dfs(int deep, int limit) {
        for(int i = deep; i < limit; ++i) { // 递归的开始均是自己与自己交换,代表“自身”这一种情况
            set.add(String.valueOf(cs));
            swap(i, deep);
            dfs(deep+1, limit); // 递归
            swap(i, deep); // 回溯
        }
    }

	// 交换字母的方法
    public void swap(int i, int j) {
        char c = cs[i];
        cs[i] = cs[j];
        cs[j] = c;
    }
}

注意点

  1. 递归的开始是自己与自己进行交换,看似做无用功,但是对于递归的整个流程而言是不可或缺的
  2. 对于在字符串上频繁进行修改的操作,不建议直接在字符串上进行操作,比如交换、替换用char[],拼接用StringBuilder对象等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值