牛客网 字符串的排列

题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

输入描述:

输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

这道题我最开始的想法是递归,每次处理一个字符,然后将其存在一个字符串里面,当字符串到了指定的长度,就把它放在一个vector里面,就可以了。但是问题来了,字符可以重复,这句话很关键。如果单纯的进行处理,最后会造成大量重复的字符串结果。我的想法是写一个判断是否重复的函数,当这个字符串重复的时候,就不压入vector了。递归的时候要注意回溯,代码如下:

class Solution {
public:
    vector<string> vec;
    vector<string> Permutation(string str) {
        
        if(str.size()<=0) return vec;
        vector<bool> visit(str.size(),false);//记录某个字符是不是已经被使用过
        vector<char> rec;
        dfs(str,visit,0,rec);
        return vec;
    }
    void dfs(string str, vector<bool> &visit, int length, vector<char> &rec){
        if(length >= str.size()){
            string tmpstr = "";
            for(int i = 0;i<rec.size();i++) tmpstr += rec[i];
            if(!findDup(vec, tmpstr)) vec.push_back(tmpstr);//看这个字符串之前是不是出现
            return;
        }
        for(int i = 0;i<str.size();i++){
            if(!visit[i]){
                visit[i] = true;
                rec.push_back(str[i]);
                dfs(str,visit,length+1,rec);
                visit[i] = false;//注意递归时候的回溯
                rec.pop_back();
            }
        }
    }
    bool findDup(vector<string> &vec, string tmpstr){//判断这个字符串是不是重复过
        for(int i = 0 ;i< vec.size();i++){
            if(tmpstr == vec[i]) return true;
        }
        return false;
    }
};

我一直觉得我这个办法不是很好,今天想到了一个更好地办法,字符交换。这样通过一个简单的判断就能避免重复的字符造成重复字符串的结果。

首先上代码:

class Solution {
public:
    vector<string> vec;
    vector<string> Permutation(string str) {
        
        if(str.size()<=0) return vec;
        helper(str,0);
        sort(vec.begin(), vec.end());
        return vec;
    }
    void helper(string &str, int i){
        if(i>= str.size()){
            vec.push_back(str);
            return;
        }
        for(int j = i;j<str.size();j++){
            if(j==i || str[j]!=str[i]){
                swap(str[i], str[j]);
                helper(str,i+1);
                swap(str[i],str[j]);
            }
        }
    }
    
};

我们来看以下这个helper函数。它的思想是用递归,每次交换两个元素。从一个整体的角度来说,求一个字符串的全排列,就是在前面一定长度的字符串长度固定的情况下,任意交换后面字符串的两个元素,最后形成总的字符串全排列。然后helper里面的循环,为什么j要从i开始而不是i+1开始呢?这是因为如果j从i+1开始,那么在for循环里面根本不会进入边界条件。换句话说,比如说“abc”这个序列,我们首先就要把这个序列自己输出,然后再考虑其他的序列组合,而j=i开始循环能保证原封不动的输出。

而str[j]!=str[i]的条件则能避免string中出现两个相同的字符造成的重复,这是因为全排列是两个任意字符交换形成的结果,那么字符一样自然就不需要交换了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值