• 剑指offer(C++)-JZ38:字符串的排列(算法-搜索算法)


    作者:翟天保Steven
    版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

    题目描述:

    输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组

    例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。

    数据范围:n<10
    要求:空间复杂度 O(n!),时间复杂度 O(n!)

    示例:

    输入:

    "aab"
    

    返回值:

    ["aab","aba","baa"]

    解题思路:

    本题考察算法-搜索算法的使用。具体实现列了三种写法:

    解法一:next_permutation函数

    1. 使用STL内置算法next_permutation,该函数会将字符串转换为下一排列。
    2. 如果对字符串先执行了排序,再循环调用next_permutation,直至字符串反序,就相当于获得了字符串从正序到反序的全排列。

    解法二:仿写next_permutation函数

    1. 考虑到很多同学想要了解next_permutation的原理逻辑,进行了仿写,仅供参考。
    2. 通过for循环,使得i最终位置是从右到左的首个正序的起始点。
    3. 若i小于0,说明此时字符串已是反序,全排序已完毕。
    4. 再通过for循环,找到比i大的字符中最小的那个,i和j交换,这样可满足字典序的全排列顺序。
    5. i和j交换后,i后面的字符串应该是反序状态,将其反转为正序,再继续找新的排列。

    解法三:深度优先遍历DFS

    1. 先字典序排序,再进行深度优先遍历获取全排列,用递归实现。
    2. 当临时字符串尺寸与输入字符串尺寸一致时,递归返回,并将当前字符串存入数组。
    3. 通过for循环,遍历所有元素,当某字符被加入到字符串了,就跳过该字符;当前的字符如果同前一个字符相同,且前面的字符还没用过,也跳过,不然会重复获取相同的字符串。
    4. 被加入的字符,将vis数组对应位置设1,作标记用,并将其加入临时字符串中。
    5. 某深度遍历完毕后,回溯到上一层,换不同的组合得到新的排列。
    6. 以此类推,直到所有的排列获取。

    测试代码:

    解法一:next_permutation函数

    1. class Solution {
    2. public:
    3. vector<string> Permutation(string str)
    4. {
    5. vector<string> ans;
    6. // 判空
    7. if (str.empty())
    8. return ans;
    9. // 排序
    10. sort(str.begin(), str.end());
    11. // 全排列,next_permutation会将str转为下一个排列
    12. do {
    13. ans.push_back(str);
    14. } while (next_permutation(str.begin(), str.end()));
    15. return ans;
    16. }
    17. };

    解法二:仿写next_permutation函数

    1. class Solution {
    2. public:
    3. vector<string> Permutation(string str)
    4. {
    5. vector<string> ans;
    6. // 判空
    7. if(str.size() == 0)
    8. return ans;
    9. // 排序
    10. sort(str.begin(),str.end());
    11. // 全排列
    12. do {
    13. ans.push_back(str);
    14. } while (nextPermutation(str));
    15. return ans;
    16. }
    17. // 变换为下个排列
    18. bool nextPermutation(string &str)
    19. {
    20. // len为字符串长度
    21. int len = str.size();
    22. // 通过for循环,使得i最终位置是从右向左的首个正序的起始点
    23. int i = len-2;
    24. for(;i>=0 && str[i]>=str[i+1];i--);
    25. // 若i小于0,说明此时字符串已是反序,全排列已完毕
    26. if(i < 0 )
    27. return false;
    28. // 通过for循环,找到比i大的字符中最小的那个,i和j交换
    29. // 交换后,i后面的字符串应该是反序状态
    30. int j = len-1;
    31. for(;j>=0 && str[j]<=str[i];j--);
    32. char temp = str[i];
    33. str[i] = str[j];
    34. str[j] = temp;
    35. // 将i后面的字符串反转成正序,继续找新的排列
    36. for(int a = i+1,b = len-1;a < b;a++,b--)
    37. {
    38. temp = str[a];
    39. str[a] = str[b];
    40. str[b] = temp;
    41. }
    42. return true;
    43. }
    44. };

    解法三:深度优先遍历DFS

    1. class Solution {
    2. public:
    3. // 深度优先遍历
    4. void DFS(vector<string> &res, string &str, string &temp, vector<int> &vis)
    5. {
    6. // 临时字符串满了加入输出
    7. if(temp.length() == str.length())
    8. {
    9. res.push_back(temp);
    10. return;
    11. }
    12. // 遍历所有字符选取一个加入
    13. for(int i = 0; i < str.length(); i++)
    14. {
    15. // 如果该字符已经被加入了则不需要再加入了
    16. if(vis[i])
    17. continue;
    18. // 当前的字符str[i]与同一层的前一个字符str[i-1]相同且str[i-1]还没用过,则跳过,避免重复
    19. if(i > 0 && str[i - 1] == str[i] && !vis[i - 1])
    20. continue;
    21. // 标记为使用过
    22. vis[i] = 1;
    23. // 加入临时字符串
    24. temp.push_back(str[i]);
    25. // 深度优先遍历
    26. DFS(res, str, temp, vis);
    27. // 回溯
    28. vis[i] = 0;
    29. temp.pop_back();
    30. }
    31. }
    32. vector<string> Permutation(string str)
    33. {
    34. // 先按字典序排序,使重复字符串相邻
    35. sort(str.begin(), str.end());
    36. // 标记每个位置的字符是否被使用过s
    37. vector<int> vis(str.size(), 0);
    38. vector<string> res;
    39. string temp;
    40. // 深度优先遍历
    41. DFS(res, str, temp, vis);
    42. return res;
    43. }
    44. };
  • 相关阅读:
    从源码中理解Spring Boot自动装配原理
    开发智能硬件过程中需要掌握的方法之经典
    商品管理模块微服务demo
    【JavaEE初阶】文件操作 和 IO (上篇)
    如何编写定时关机脚本以保护服务器安全
    深度学习,从一维特性输入到多维特征输入引发的思考(未完成)
    gpu cuda 矩阵乘法
    参考线平滑-FemPosDeviation-SQP
    git使用
    【Android-实战】1、Room 使用 Flow 和 collect() 监听数据库的变化、动态更新页面
  • 原文地址:https://blog.csdn.net/zhaitianbao/article/details/126766204