面试题38:字符串的排列(C++)

题目地址:https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof/

题目描述

输入一个字符串,打印出该字符串中字符的所有排列。你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。

题目示例

示例:

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

解题思路

面试题38:字符串的排列(C++)_第1张图片

字符串排列和数字排列问题都属于回溯的经典问题

面试题38:字符串的排列(C++)_第2张图片

具体过程可参考上图(图源https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof/solution/c-by-bu-hui-coding-44/)

STL:使用函数next_permutation(start,end)求得当前排列的下一个排列

递归回溯(全排列):定义回溯函数back_track,在决策树上遍历,并维护每个点的属性,每当走到树的底层,其路径便是一全排列。需要注意的是当字符出现重复时,需要去重,在这里我们使用flag数组标识当前元素是否已被访问过,初始默认均未访问,即初始化0,当访问之后,则初始化为1。另外一点就是需要首先对字符串进行排序,以此来使重复的字符相邻。最后,当节点未被访问且相邻字符不是重复字符时,将该字符加入排列字符串中,依次递归遍历。

交换法:如图所示,分割字符串"ABC",每个固定一个字符为一部分,其他字符为另一部分,再将固定字符与其他字符进行交换,依次遍历每个字符,再进行回溯递归。

程序源码

STL

class Solution {
public:
    vector<string> permutation(string s) {
        if(s.empty()) return {};
        sort(s.begin(), s.end());
        vector<string> res;
        res.push_back(s);
        while(next_permutation(s.begin(), s.end())){
            res.push_back(s);
        }
        return res;
    }
};

递归回溯

class Solution {
public:
    vector<string> res;
    vector<int> flag;
    vector<string> permutation(string s) {
        if(s.empty()) return {};
        sort(s.begin(), s.end());
        flag = vector<int>(s.size(), '0');
        string str = "";
        back_track(s, 0, str);
        return res;
    }
    void back_track(string s, int index,  string track)       {
        if (s.size() == track.size()) { //回溯结束条件
            res.push_back(track);
            return;
        }
        for (int i = 0; i < s.size(); i++) {
            if (flag[i] == '1') continue; //当前值已被使用,则跳过
            if(i-1 >= 0 && s[i] == s[i-1] && flag[i-1] == '1') continue; //当前值和前一个值相等,并且前一个值已被使用,则跳过,比如aab
            flag[i] = '1';
            back_track(s, index+1, track+s[i]);
            flag[i] = '0';
        }
    }
   
};

交换法

class Solution {
public:
    vector<string> permutation(string s) {
        if(s.empty()) return {};
        set<string> res; //去重
        back_track(s, 0, res);
        return vector<string>(res.begin(), res.end());
    }
    void back_track(string s, int begin, set<string> &res)
    {
        if(begin == s.size())
        {
            res.insert(s);
            return;
        }
        for(int i = begin; i < s.size(); i++)
        {
            swap(s[i], s[begin]); //做出选择
            back_track(s, begin + 1, res); //进入下次决策树
            swap(s[i], s[begin]); //撤回选择
        }
    }
};
 

参考文章

https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof/solution/hui-su-fa-by-luo-jing-yu-yu/

你可能感兴趣的:(面试题38:字符串的排列(C++))