剑指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;
    }
};


相关文章
|
2月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】基于非支配排序的鲸鱼优化算法NSWOA与多目标螳螂搜索算法MOMSA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】基于非支配排序的鲸鱼优化算法NSWOA与多目标螳螂搜索算法MOMSA求解无人机三维路径规划研究(Matlab代码实现)
188 5
|
2月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】多目标螳螂搜索算法MOMSA与非支配排序的鲸鱼优化算法NSWOA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】多目标螳螂搜索算法MOMSA与非支配排序的鲸鱼优化算法NSWOA求解无人机三维路径规划研究(Matlab代码实现)
152 0
|
1月前
|
算法 数据可视化 测试技术
HNSW算法实战:用分层图索引替换k-NN暴力搜索
HNSW是一种高效向量检索算法,通过分层图结构实现近似最近邻的对数时间搜索,显著降低查询延迟。相比暴力搜索,它在保持高召回率的同时,将性能提升数十倍,广泛应用于大规模RAG系统。
140 10
HNSW算法实战:用分层图索引替换k-NN暴力搜索
|
3月前
|
机器学习/深度学习 算法 文件存储
神经架构搜索NAS详解:三种核心算法原理与Python实战代码
神经架构搜索(NAS)正被广泛应用于大模型及语言/视觉模型设计,如LangVision-LoRA-NAS、Jet-Nemotron等。本文回顾NAS核心技术,解析其自动化设计原理,探讨强化学习、进化算法与梯度方法的应用与差异,揭示NAS在大模型时代的潜力与挑战。
885 6
神经架构搜索NAS详解:三种核心算法原理与Python实战代码
|
2月前
|
存储 算法 数据可视化
基于禁忌搜索算法的TSP问题最优路径搜索matlab仿真
本程序基于禁忌搜索算法解决旅行商问题(TSP),旨在寻找访问多个城市的最短路径。使用 MATLAB 2022A 编写,包含城市坐标生成、路径优化及结果可视化功能。通过禁忌列表、禁忌长度与藐视准则等机制,提升搜索效率与解的质量,适用于物流配送、路径规划等场景。
|
4月前
|
C语言 C++
【实战指南】 C/C++ 枚举转字符串实现
本文介绍了在C/C++中实现枚举转字符串的实用技巧,通过宏定义与统一管理枚举名,提升代码调试效率并减少维护错误。
343 52
|
3月前
|
机器学习/深度学习 并行计算 算法
MATLAB实现利用禁忌搜索算法解决基站选址问题
MATLAB实现利用禁忌搜索算法解决基站选址问题
148 0
|
4月前
|
存储 搜索推荐 算法
加密算法、排序算法、字符串处理及搜索算法详解
本文涵盖四大类核心技术知识。加密算法部分介绍了对称加密(如 AES)、非对称加密(如 RSA)、哈希摘要(如 SHA-2)、签名算法的特点及密码存储方案(加盐、BCrypt 等)。 排序算法部分分类讲解了比较排序(冒泡、选择、插入、归并、快排、堆排序)和非比较排序(计数、桶、基数排序)的时间复杂度、适用场景及实现思路,强调混合排序的工业应用。 字符串处理部分包括字符串反转的双指针法,及项目中用正则进行表单校验、网页爬取、日志处理的实例。 搜索算法部分详解了二分查找的实现(双指针与中间索引计算)和回溯算法的概念(递归 + 剪枝),以 N 皇后问题为例说明回溯应用。内容全面覆盖算法原理与实践
182 0
|
4月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
150 0
|
6月前
|
监控 算法 数据处理
基于 C++ 的 KD 树算法在监控局域网屏幕中的理论剖析与工程实践研究
本文探讨了KD树在局域网屏幕监控中的应用,通过C++实现其构建与查询功能,显著提升多维数据处理效率。KD树作为一种二叉空间划分结构,适用于屏幕图像特征匹配、异常画面检测及数据压缩传输优化等场景。相比传统方法,基于KD树的方案检索效率提升2-3个数量级,但高维数据退化和动态更新等问题仍需进一步研究。未来可通过融合其他数据结构、引入深度学习及开发增量式更新算法等方式优化性能。
183 17

热门文章

最新文章