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

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

题目描述:

输入一个长度为 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函数

class Solution {
public:
    vector<string> Permutation(string str) 
    {
        vector<string> ans;
        // 判空
        if (str.empty()) 
            return ans;
        // 排序
        sort(str.begin(), str.end());
        // 全排列,next_permutation会将str转为下一个排列
        do {
            ans.push_back(str);
        } while (next_permutation(str.begin(), str.end()));
        return ans;
    }    
};

解法二:仿写next_permutation函数

class Solution {
public:
    vector<string> Permutation(string str) 
    {
        vector<string> ans;
        // 判空
        if(str.size() == 0)
            return ans;
        // 排序
        sort(str.begin(),str.end());
        // 全排列
        do {
            ans.push_back(str);
        } while (nextPermutation(str));
        return ans;
    }
    // 变换为下个排列
    bool nextPermutation(string &str) 
    {
        // len为字符串长度
        int len = str.size();
        // 通过for循环,使得i最终位置是从右向左的首个正序的起始点
        int i = len-2;
        for(;i>=0 && str[i]>=str[i+1];i--);
        // 若i小于0,说明此时字符串已是反序,全排列已完毕
        if(i < 0 )
            return false;
        // 通过for循环,找到比i大的字符中最小的那个,i和j交换
        // 交换后,i后面的字符串应该是反序状态
        int j = len-1;
        for(;j>=0 && str[j]<=str[i];j--);
        char temp = str[i];
        str[i] = str[j];
        str[j] = temp;
        // 将i后面的字符串反转成正序,继续找新的排列
        for(int a = i+1,b = len-1;a < b;a++,b--)
        {
            temp = str[a];
            str[a] = str[b];
            str[b] = temp;
        }
        return true;
    }
};

解法三:深度优先遍历DFS

class Solution {
public:
    // 深度优先遍历
    void DFS(vector<string> &res, string &str, string &temp, vector<int> &vis)
    {
        // 临时字符串满了加入输出
        if(temp.length() == str.length())
        { 
            res.push_back(temp);
            return;
        }
        // 遍历所有字符选取一个加入
        for(int i = 0; i < str.length(); i++)
        { 
            // 如果该字符已经被加入了则不需要再加入了
            if(vis[i]) 
                continue;
            // 当前的字符str[i]与同一层的前一个字符str[i-1]相同且str[i-1]还没用过,则跳过,避免重复
            if(i > 0 && str[i - 1] == str[i] && !vis[i - 1])
                continue;
            // 标记为使用过  
            vis[i] = 1;  
            // 加入临时字符串
            temp.push_back(str[i]); 
            // 深度优先遍历
            DFS(res, str, temp, vis);
            // 回溯
            vis[i] = 0; 
            temp.pop_back();
        }
    }
    vector<string> Permutation(string str) 
    {
        // 先按字典序排序,使重复字符串相邻
        sort(str.begin(), str.end()); 
        // 标记每个位置的字符是否被使用过s
        vector<int> vis(str.size(), 0); 
        vector<string> res;
        string temp;
        // 深度优先遍历
        DFS(res, str, temp, vis); 
        return res;
    }
};


相关文章
|
8天前
|
消息中间件 Linux C++
c++ linux通过实现独立进程之间的通信和传递字符串 demo
的进程间通信机制,适用于父子进程之间的数据传输。希望本文能帮助您更好地理解和应用Linux管道,提升开发效率。 在实际开发中,除了管道,还可以根据具体需求选择消息队列、共享内存、套接字等其他进程间通信方
39 16
|
1天前
|
算法
基于SOA海鸥优化算法的三维曲面最高点搜索matlab仿真
本程序基于海鸥优化算法(SOA)进行三维曲面最高点搜索的MATLAB仿真,输出收敛曲线和搜索结果。使用MATLAB2022A版本运行,核心代码实现种群初始化、适应度计算、交叉变异等操作。SOA模拟海鸥觅食行为,通过搜索飞行、跟随飞行和掠食飞行三种策略高效探索解空间,找到全局最优解。
|
1月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
49 2
|
2月前
|
存储 算法 安全
基于红黑树的局域网上网行为控制C++ 算法解析
在当今网络环境中,局域网上网行为控制对企业和学校至关重要。本文探讨了一种基于红黑树数据结构的高效算法,用于管理用户的上网行为,如IP地址、上网时长、访问网站类别和流量使用情况。通过红黑树的自平衡特性,确保了高效的查找、插入和删除操作。文中提供了C++代码示例,展示了如何实现该算法,并强调其在网络管理中的应用价值。
|
1月前
|
存储 算法 安全
基于哈希表的文件共享平台 C++ 算法实现与分析
在数字化时代,文件共享平台不可或缺。本文探讨哈希表在文件共享中的应用,包括原理、优势及C++实现。哈希表通过键值对快速访问文件元数据(如文件名、大小、位置等),查找时间复杂度为O(1),显著提升查找速度和用户体验。代码示例展示了文件上传和搜索功能,实际应用中需解决哈希冲突、动态扩容和线程安全等问题,以优化性能。
|
3月前
|
算法 搜索推荐 数据库
二分搜索:高效的查找算法
【10月更文挑战第29天】通过对二分搜索的深入研究和应用,我们可以不断挖掘其潜力,为各种复杂问题提供高效的解决方案。相信在未来的科技发展中,二分搜索将继续发挥着重要的作用,为我们的生活和工作带来更多的便利和创新。
81 1
|
4月前
|
算法
两个字符串匹配出最长公共子序列算法
本文介绍了最长公共子序列(LCS)问题的算法实现,通过动态规划方法求解两个字符串的最长公共子序列,并提供了具体的编程实现细节和示例。
135 1
两个字符串匹配出最长公共子序列算法
|
4月前
|
算法 决策智能
基于禁忌搜索算法的VRP问题求解matlab仿真,带GUI界面,可设置参数
该程序基于禁忌搜索算法求解车辆路径问题(VRP),使用MATLAB2022a版本实现,并带有GUI界面。用户可通过界面设置参数并查看结果。禁忌搜索算法通过迭代改进当前解,并利用记忆机制避免陷入局部最优。程序包含初始化、定义邻域结构、设置禁忌列表等步骤,最终输出最优路径和相关数据图表。
|
4月前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
1145 0
高精度算法(加、减、乘、除,使用c++实现)
|
4月前
|
缓存 网络协议 API
C/C++ StringToAddress(字符串转 boost::asio::ip::address)
通过上述步骤和示例代码,你可以轻松地在C++项目中实现从字符串到 `boost::asio::ip::address`的转换,从而充分利用Boost.Asio库进行网络编程。
146 0