剑指Offer! 38.字符串的排列,深度优先遍历

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

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

示例:

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

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

思路:
这应该是剑指offer这本书上的思路,把全排列问题转化成“遍历字符串,并替换两个字符”。
关键点是去重。
如果不去重的话,
如"abscajoaka"第一个’a’作pivot时,欲固定位置0上的字符,pivot可以和它之后的任意字符chs[i](包含它本身)做替换生成新的字符串,在此基础上分析位置1处的字符’b’为pivot时的情况(欲固定位置1上的字符)。
去重交给notSame方法实现:
如果pivot到chs[i]之间存在和chs[i]相同的字符,那么跳过这个chs[i],表示chs[i]已经登录过pivot所在位置了。
比如上面的"abscajoaka",pivot='b’时,chs[7]=‘a’,由于他们之间存在和chs[7]相同的字符chs[4],那么chs[4]必然在chs[7]与pivot发生交换之前与pivot交换,所以chs[7]与pivot会产生重复的分支,于是剪枝去重。
a b s c a j o a k a // chs
0 1 2 3 4 5 6 7 8 9 // i

 public String[] permutation(String s) {
        ArrayList<String> res = new ArrayList<>();
        char[] chs = s.toCharArray();
        f(chs,0,res);// the 2nd argument means the index of pivot 
        
        return res.toArray(new String[0]);
    }
    public void f(char[] chs,int index, ArrayList<String> res){
        if(index==chs.length){
            String temp = new String(chs);       
            res.add(temp);        
            return;
        }
        for(int i=index;i<chs.length;i++){
            if(notSame(chs,index,i)){ // 去重
            swap(chs,i, index);
            f(chs,index+1,res);
            swap(chs,i,index);
            }
           
        }      

    }
    public void swap(char[] chs, int i,int j){
        char ch = chs[i];
        chs[i]=chs[j];
        chs[j]=ch;
    }
    public boolean notSame(char[] chs, int start, int end){// 注意,精妙之处在于当start==end时,return false, 这样也会收录 “位置index上依然是字符chs[index]” 的答案,比如 “abcd”, when index=0, we wil have subAnswers like "acbd","adcb",... and so on, which means chs[0] still is allowed to stay at 0.
        for(int i=start;i<end;i++){
            if(chs[i]==chs[end]){
                return false;
            }
        }
        return true;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值