剑指 Offer 38. 字符串的排列

本文详细介绍了两种解决字符串全排列问题的算法:回溯法和下一个排列法。通过这两种方法,可以有效地生成给定字符串的所有不重复排列。代码示例分别用C++实现了这两种算法,确保了排列的唯一性。对于回溯法,利用了递归和标记避免重复;对于下一个排列法,利用了`next_permutation()`函数。这两种方法都适用于字符串长度不超过8的情况。

字符串的排列


题目链接: 剑指 Offer 38. 字符串的排列

有关题目

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

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

1 <= s 的长度 <= 8

题解

法一:回溯

思路:
将这个问题看作有 n 个排列成一行的空位,我们需要从左往右
依次填入题目给定的 n 个字符,每个字符只能使用一次。
使用穷举法从左往右,依次填入字符
class Solution {
public:
    //创建全局变量数组,减少回溯函数传参
    vector<string> rec;
    vector<int> vis;
    void backtrack(const string& s,int i,int n,string& perm)
    //s 获得全排列的源字符串 i 下一个待填入的空位是第 i 个空位
    //n  = s.length()   perm 当前排序
    {
        if (i == n)//递归终止条件
            {
                rec.push_back(perm);
                return;
            }
        else
        {
            for (int j = 0; j < n; j++)
            {
                //在递归函数中,我们限制每次填入的字符一定是这个字符所在重复字符集合中「从左往右第一个未被填入的字符」保证生成不重复序列的必要条件
                if ((vis[j] || (j > 0 && !vis[j - 1] && s[j - 1] == s[j])))
                    continue;
                vis[j] = true;//标记
                perm.push_back(s[j]);
                backtrack(s,i + 1,n,perm);
                perm.pop_back();//拿掉上一个函数,防止数据污染
                vis[j] = false;//使用完,拿掉标记
            }
        }

    }

    vector<string> permutation(string s) {
        int n = s.length();
        vis.resize(n);
        sort(s.begin(),s.end());//给字符串排序,保证生成不重复序列的必要条件
        string perm;//定义backtrack函数中的当前 排序
        backtrack(s,0,n,perm);//调用回溯函数
        return rec;
    }
};

在这里插入图片描述
法二:下一个排列

思路:
结合next_permutation()函数思想,避免分类讨论,找出的一定是避免重复的字符串,下图附next_permutation函数的排列顺序

在这里插入图片描述

class Solution {
public:
    bool nextPermutation(string& s)
    {
        int i = s.length() - 2;
        while(i >= 0 && s[i] >= s[i + 1])
            --i;
        if (i < 0)
            return false;
        int j = s.length() - 1;
        while(j >= 0 && s[i] >= s[j])
            --j;

        swap(s[i],s[j]);
        reverse(s.begin() + i + 1,s.end());
        return true;
    }
    vector<string> permutation(string s) {
        vector<string> ret;
        sort(s.begin(),s.end());
        do
        {
            ret.push_back(s);
        }while(nextPermutation(s));
        return ret;
    }
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值