字符串的排列

字符串的排列

http://www.nowcoder.com/questionTerminal/fe6b651b66ae47d7acce78ffdd9a96c7

描述

这是一篇针对初学者的题解,用递归方法解决。
知识点:字符串,递归,回溯
难度:一星


题解

题目抽象:给定一个字符串,求该字符串的全排列。

方法:递归法

如图:

如图所示的全排列可以发现,
图片说明
对于这个排列,我们是固定A不动,然后交换B与C,从而得到"ABC" 和 "ACB"
同理,对于"BAC"、"BCA" 、"CAB"和"CBA"是同样道理

递归三部曲:

  1. 递归函数的功能:dfs(int pos, string s), 表示固定字符串spos下标的字符s[pos]
  2. 递归终止条件:当pos+1 == s.length()的时候,终止,表示对最后一个字符进行固定,也就说明,完成了一次全排列
  3. 下一次递归:dfs(pos+1, s), 很显然,下一次递归就是对字符串的下一个下标进行固定

但是,对于"ABB"来说,就会有重复,如图
图片说明
所以,我们用set可以进行去重,并且可以达到按字母顺序排序。

代码

class Solution {
public:
    void perm(int pos, string s, set<string> &ret) {
        if (pos+1 == s.length()) {
            ret.insert(s);
            return;
        }
        // for循环和swap的含义:对于“ABC”,
        // 第一次'A' 与 'A'交换,字符串为"ABC", pos为0, 相当于固定'A'
        // 第二次'A' 与 'B'交换,字符串为"BAC", pos为0, 相当于固定'B'
        // 第三次'A' 与 'C'交换,字符串为"CBA", pos为0, 相当于固定'C'
        for (int i = pos; i < s.length(); ++i) {
            swap(s[pos], s[i]);
            perm(pos+1, s, ret);
            swap(s[pos], s[i]);
            // 回溯的原因:比如第二次交换后是"BAC",需要回溯到"ABC"
            // 然后进行第三次交换,才能得到"CBA"
        }
    }
    vector<string> Permutation(string s) { 
        if (s.empty()) return {};
        set<string> ret;
        perm(0, s, ret);
        return vector<string>({ret.begin(), ret.end()});
    }
};

时间复杂度:O(n!),比如3个字符的全排列有6种
空间复杂度:O(1),原地交换

全部评论
这个人发布的答案啥都是一星难度。。。。
10 回复 分享
发布于 2021-04-15 21:40
为什么空间复杂度是O(1),使用了额外的空间set 啊 应该是O(n!)吧
4 回复 分享
发布于 2020-07-14 07:20
这也没按字典序吧?
4 回复 分享
发布于 2020-07-29 20:24
for循环应该是i++吧,不然A与A没法呼唤,而且其他每个字母的开头的结果会少一个结果,因为提前结束了循环
3 回复 分享
发布于 2020-06-27 23:02
你递归不算空间开销的?
3 回复 分享
发布于 2020-12-03 11:29
C++的set是ordered? java我试了用set保存结果顺序变了因为java里面set是不能保证顺序的
2 回复 分享
发布于 2020-07-31 14:52
if (pos+1 == s.length())的pos为什么要+1,不+1也是可以通过的
1 回复 分享
发布于 2020-07-03 07:49
我TM,直接复制过去都不能通过,warning: comparison of integers of different signs: 'int' and 'size_type' (aka 'unsigned long') [-Wsign-compare] if (pos+1 == s.length())
1 回复 分享
发布于 2020-08-18 21:58
编译不通过怎么回事
1 回复 分享
发布于 2020-10-05 00:31
用set感觉好耍赖
1 回复 分享
发布于 2021-06-01 15:29
另外通过调换位置没法生成的结果是字典排序
点赞 回复 分享
发布于 2020-07-31 16:45
Java直接就用ArrayList保存就好,输出前需要排个序,应该程序存储的顺序就不是字典序
点赞 回复 分享
发布于 2020-08-05 16:30
这个不是相当于直接得到一个任意序列的数组,然后又对这个数组进行排序了一样吗
点赞 回复 分享
发布于 2020-10-15 19:53
所以……java或者其他语言要怎么按字典序输出……暴力排序么???
点赞 回复 分享
发布于 2020-11-02 00:21
答案有问题,空间复杂度不是O(1)
点赞 回复 分享
发布于 2020-12-26 02:05
妙啊
点赞 回复 分享
发布于 2021-01-29 15:09
回溯是多余的
点赞 回复 分享
发布于 2021-06-26 18:39
class Solution { public: vector<string> Permutation(string str) { string ans; int len=str.size(); bool used[len]; memset(used,0 ,sizeof(used)); vector<string> ret; // sort(str.begin(), str.end()); DFS(str,ret,ans,used,len,0); return ret; } void DFS( const string &str,vector<string>&ret,string &ans,bool used[],int len,int depth){ if(depth==len){ ret.push_back(ans); return; } for(int i=0;i<len>0&&!used[i]&&str[i]==str[i-1])){ continue; } used[i]=true; ans.push_back(str[i]); DFS(str,ret,ans,used,len,depth+1); ans.pop_back(); used[i]=false; } } }; 请问这个代码哪里有错误 没看出来,根据leecode思想来的DFS回溯</len></string></string></string>
点赞 回复 分享
发布于 2021-07-01 21:10
好厉害啊,想不出来
点赞 回复 分享
发布于 2021-09-06 22:33
这个感觉就是暴力枚举的呀
点赞 回复 分享
发布于 2021-10-24 19:39

相关推荐

小红书 后端开发 总包n+8w+期权
点赞 评论 收藏
分享
我已成为0offer的糕手:别惯着,胆子都是练出来的,这里认怂了,那以后被裁应届被拖工资还敢抗争?
点赞 评论 收藏
分享
评论
90
14
分享
牛客网
牛客企业服务