剑指offer38:字符串的全排列

前言:感觉自己最近过得很放松,很放纵,学习态度很不好。
认准了目标,只有坚持不懈,付出120%的努力去做,才能取得成功。

剑指offer P197

注意审题!
给出三种不同的解。
其中还是经典的回溯+剪枝的方法效果最好。
对于此题,回溯法很简单很自然使用一个bool数组来记录dfs过程中那些字符被使用,另外剪枝过程的分析为使得每一轮选择中,不同的字符只选择一次而不考虑该字符出现在原字符串中的位置。
代码如下:

//
// Created by wbzhang on 2020/8/6.
//
#include "../common/common.h"

// 回溯+剪枝方法
class Solution {
public:
    vector<string> res; //保存结果
    int length;

    // 当前路径,当前
    void backTrack(string &cur,vector<bool> &path,string s){
        // 截止条件
        if(cur.size()==s.size()){
            res.push_back(cur);
            return;
        }
        // 选择列表
        for(int i=0;i<length;++i){
            if(path[i] ) continue; //已使用,或该轮中此种选择已经做过
            // 剪枝
            if(i > 0 && !path[i-1] && s[i-1] == s[i]) continue;

            // 做选择
            cur.push_back(s[i]);
            path[i] = true;
            
            backTrack(cur,path,s);
            // 回溯
            cur.pop_back();
            path[i] = false;
        }
    }

    vector<string> permutation(string s) {
        // 特别判断
        if(!s.size()) return {};
        this->length = s.size();
        // 排序
        sort(s.begin(),s.end());
        // 回溯法
        string cur ="";
        // int cur_pose = 0;
        vector<bool> path(s.length(),false); // 当前使用过的元素
        backTrack(cur,path,s);

        return res;
    }


};

// 仅排列不同字符的解
class Solution2 {
public:
    set<string> res; //保存结果
    int length;

    // 当前路径,当前
    void backTrack(string &cur,vector<bool> &path,string s){
        // 截止条件
        if(cur.size()==s.size()){
            res.insert(cur);
            return;
        }
        // 选择列表
        for(int i=0;i<length;++i){
            if(path[i]) continue; //已使用
            // 做选择
            cur.push_back(s[i]);
            path[i] = true;
            backTrack(cur,path,s);
            // 回溯
            cur.pop_back();
            path[i] = false;
        }
    }

    vector<string> permutation(string s) {
        // 特别判断
        if(!s.size()) return {};
        // 否则,统计s中不同的字母
        int diffChars[256]={0};
        string diffS="";
        for(auto ele:s){
            if(diffChars[ele]==0){
                diffChars[ele]=1;
                diffS.push_back(ele);
            }
        }

        this->length = diffS.size();
        // 回溯法
        string cur ="";
        // int cur_pose = 0;
        vector<bool> path(diffS.length(),false); // 当前使用过的元素
        backTrack(cur,path,diffS);

        vector<string> ans(this->res.begin(),this->res.end());
        return ans;
    }


};

// 暴力使用set容器去重的方法,缺点在于不如剪枝后的复杂度好
class Solution3 {
public:
    set<string> res; //保存结果
    int length;

    // 当前路径,当前
    void backTrack(string &cur,vector<bool> &path,string s){
        // 截止条件
        if(cur.size()==s.size()){
            res.insert(cur);
            return;
        }
        // 选择列表
        for(int i=0;i<length;++i){
            if(path[i]) continue; //已使用
            // 做选择
            cur.push_back(s[i]);
            path[i] = true;
            backTrack(cur,path,s);
            // 回溯
            cur.pop_back();
            path[i] = false;
        }
    }

    vector<string> permutation(string s) {
        // 特别判断
        if(!s.size()) return {};
        this->length = s.size();
        // 回溯法
        string cur ="";
        // int cur_pose = 0;
        vector<bool> path(s.length(),false); // 当前使用过的元素
        backTrack(cur,path,s);

        vector<string> ans(this->res.begin(),this->res.end());
        return ans;
    }


};

int main(){
    string s="aab";
    Solution solu;
    vector<string> res = solu.permutation(s);

    for(auto ele:res){
        cout<<ele<<"\t"<<endl;
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值