字符串的排列组合

DESC1:

无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。

示例1:

 输入:S = "qwe"
 输出:["qwe", "qew", "wqe", "weq", "ewq", "eqw"]

示例2:

 输入:S = "ab"
 输出:["ab", "ba"]

提示:

    字符都是英文字母。
    字符串长度在[1, 9]之间。

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

CODE:

JAVA:

class Solution {
    public String[] permutation(String S) {
        if (S == null || S.length() == 0) {
            return new String[0];
        }
        char[] arr = S.toCharArray();
        boolean[] flag = new boolean[arr.length];
        List<String> res = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        backTrack(res, arr, flag, sb);
        String[] temp = new String[res.size()];
        for (int i=0; i<res.size(); i++) {
            temp[i] = res.get(i);
        }
        return temp;
    }

    public void backTrack(List<String> res, char[] arr, boolean[] flag, StringBuilder sb) {
        if (sb.length() == arr.length) {
            res.add(sb.toString());
            return;
        }
        for (int i=0; i<arr.length; i++) {
            //已走过,跳过 q-[q(跳过),w,e]
            if (flag[i]) {
                continue;
            }
            sb.append(arr[i]);
            flag[i] = true;
            backTrack(res, arr, flag, sb);//如q-w这一条路径方向
            flag[i] = false;//q-w走完,下一次该走q-e,所以需要将flag中w恢复,sb也要移除w
            sb.deleteCharAt(sb.length()-1);//注意deleteCharAt,非remove
        }
    }
}

NOTES:

  1. 回溯思想,递归
  2. 第一队列遍历每个字符,然后以每个字符为起始点,第二队列,再次递归每个字符进行追加,遇到第一队列已走过的点跳过,然后再进入第三队列迭代递归,所以需要一个状态数组来记录追加路径中已走过的点
  3. 重要的是,在同一队列中,某节点走完其路径,要注意回溯到队列之前状态,在进行下一节点递归,如第一队列为q点,进入第二队列,q,w,e三个节点,q在第一队列已走过直接跳过,走w节点,此时q-w路径开始递归进入第三队列获取所有队列,结束后,继续第二队列,此时需要将w节点的状态置为false,路径中移除,恢复到第二队列的进入状态,才可进行下一节点q-e的迭代。也就是所谓的回溯思想~
  4. 结束条件,就是路径的长度等于字符串的长度,说明都走过了;

进阶,假如字符串并不是非重复的,可能包含重复字符,怎么解~

DESC2:

有重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合。

示例1:

 输入:S = "qqe"
 输出:["eqq","qeq","qqe"]

示例2:

 输入:S = "ab"
 输出:["ab", "ba"]

提示:

    字符都是英文字母。
    字符串长度在[1, 9]之间。

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

CODE:

JAVA:

class Solution {
    public String[] permutation(String S) {
        if (S == null || S.length()==0) {
            return new String[0];
        }
        char[] arr = S.toCharArray();
        //排序,是重复字符挨在一起
        Arrays.sort(arr);

        boolean[] flag = new boolean[arr.length];
        List<String> resList = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        backTrack(resList, arr, flag, sb);
        
        String[] res = new String[resList.size()];
        for (int i=0; i<resList.size(); i++) {
            res[i] = resList.get(i);
        }
        return res;
    }

    public void backTrack(List<String> resList, char[] arr, boolean[] flag, StringBuilder sb) {
        if (sb.length() == arr.length) {
            resList.add(sb.toString());
            return;
        }

        for (int i=0; i<arr.length; i++) {
            //如果再同一队列中,如abbbc,两个bb产生的路径是一样的,所以后面的跳过
            if (flag[i] || (i>0 && arr[i] == arr[i-1] && !flag[i-1])) {
                continue;
            }
            sb.append(arr[i]);
            flag[i] = true;
            backTrack(resList, arr, flag, sb);
            flag[i] = false;
            sb.deleteCharAt(sb.length()-1);
        }
    }
}

NOTES:

  1. 有重复字符,如果还是和题一一样,肯定会有重复序列,所以需要去重,首先对字符序列排序,使重复字符挨着;
  2. 重复序列产生的时机是在同一队列遍历时,如bbbc,在第一队列[b,b,b,c]中,三个以b开头的节点产生的路径肯定是一样的,所以只走一个就好。即当满足(i>0 && arr[i] == arr[i-1])条件时,说明碰上了重复字符,则跳过;这样是否就可以了呢,仔细想想或者画一画你会发现在第二队列,正常的路径也被跳过了,所以需要加上 && !flag[i-1]条件,即需满足不是在跨队列正常的路径中。如bbbc这个b-b(1)-跳过,是因为第一队列已走过, 但b-b(2)-不能被过滤,1,2代表第二队列第一个字符,b-b(3)-重复过滤;
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值