LeetCode 剑指Offer38 字符串的排列

题目链接:LeetCode 剑指Offer38 字符串的排列

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

题解:

回溯

通过搜索和回溯枚举所有的排列情况,但会有重复的情况。
只要在递归函数中设定一个规则,保证在填每一个空位的时候重复字符只会被填入一次。具体地,我们首先对原字符串排序,保证相同的字符都相邻,在递归函数中,我们限制每次填入的字符一定是这个字符所在重复字符集合中“从左往右第一个未被填入的字符”,即如下的判断条件:

if (vis[j] || (j > 0 && !vis[j - 1] && s[j - 1] == s[j])) {
    continue;
}

这个限制条件保证了对于重复的字符,我们一定是从左往右依次填入的空位中的。

class Solution {
private:
    vector<string> ans;
    vector<int> vis;

public:
    void backtrack(const string& s, int i, int n, string& now) {
        if (i == n) {
            ans.push_back(now);
            return;
        }
        for (int j = 0; j < n; j++) {
            if (vis[j] || (j > 0 && !vis[j - 1] && s[j - 1] == s[j])) {
                continue;
            }
            vis[j] = true;
            now.push_back(s[j]);
            backtrack(s, i + 1, n, now);
            now.pop_back();
            vis[j] = false;
        }
    }

    vector<string> permutation(string s) {
        int n = s.size();
        vis.resize(n);
        sort(s.begin(), s.end());
        string now;
        backtrack(s, 0, n, now);
        return ans;
    }
};

尺取法

按字典序从小到大寻找字符排列,注意到下一个排列总是比当前排列要大,除非该排列已经是最大的排列。我们希望找到一种方法,能够找到一个大于当前序列的新序列,且变大的幅度尽可能小。具体地:

  1. 我们需要将一个左边的“较小数”与一个右边的“较大数”交换,以能够让当前排列变大,从而得到下一个排列。
  2. 同时我们要让这个“较小数”尽量靠右,而“较大数”尽可能小。当交换完成后,“较大数”右边的数需要按照升序重新排列。这样可以在保证新排列大于原来排列的情况下,使变大的幅度尽可能小。

具体地,我们这样描述该算法,对于长度为\(n\)的排列\(a\):

  1. 首先从后向前查找第一个顺序对\((i,i+1)\),满足\(a[i]<a[i+1]\)。这样“较小数”即为\(a[i]\)。此时\([i+1,n)\)必然是下降序列。
  2. 如果找到了顺序对,那么在区间\([i+1,n)\)中从后向前查找第一个元素\(j\)满足\(a[i]<a[j]\)。这样“较大数”即为\(a[j]\)。
  3. 交换\(a[i]\)与\(a[j]\),此时可以证明区间\([i+1,n)\)必为降序。我们可以直接使用双指针反转区间\([i+1,n)\)使其变为升序,而无需对该区间进行排序。
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 (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> ans;
        sort(s.begin(), s.end());
        do {
            ans.push_back(s);
        } while (nextPermutation(s));
        return ans;
    }
};
上一篇:SSM开发书评网17:图书详情页开发一:读取图书信息;


下一篇:ssm框架复习巩固