美文网首页
LC60 Permutation Sequence

LC60 Permutation Sequence

作者: Rookie118 | 来源:发表于2020-06-24 17:05 被阅读0次

本题链接:Permutation Sequence

本题标签:Math, Backtracking

本题难度:\color{Orange}{Medium}

英文题目 中文题目

方案1: 利用 Next Permutation 代码

class Solution {
private:
    void nextPermutation(vector<int>& nums) {
        if(nums.empty() || nums.size() == 1)
            return;
        
        int left = -1, right = -1;
        for(int i = nums.size() - 2; i >= 0; --i)
        {
            if(nums[i] < nums[i+1])
            {
                left = i;
                break;
            }
        }
        if(left == -1)
        {
            reverse(nums.begin(), nums.end());
            return;
        }
            
        for(int i = nums.size() - 1; i > left; --i)
        {
            if(nums[i] > nums[left])
            {
                right = i;
                break;
            }
        }
        swap(nums[left], nums[right]);
        reverse(nums.begin() + left + 1, nums.end());
    }
public:
    string getPermutation(int n, int k) {
        string res;
        vector<int> nums;
        for(int i = 1; i <= n; ++i)
            nums.push_back(i);
        
        for(int j = 1; j < k; ++j)
            nextPermutation(nums);
        
        for(auto n : nums)
            res.push_back(n + '0');
        return res;
    }
};

时间复杂度:O ( N K )

空间复杂度:O ( N )


方案2: 根据观察得到的数学规律

Permutation Index k
“123” 0 1
“132” 1 2
“213” 2 3
“231” 3 4
“312” 4 5
“321” 5 6

我们可以看到当n = 3时,总共有6种排列情况。而且这6种情况又可以分为首位数字为1、2、3这3种类别,每种类别各有2种。换句话说,当我们把首位数字固定之后,剩余2位数字的排列就是2!= 2种情况。
然后当k = 3时,即选择第三种排列“213”时,我们可以发现这种情况属于首位数字为2的类别。而首位数字为2这种类别对应的下标Index范围为[2, 3]。所以为了找到这个数字2,我们需要找出对应的数学公式。
我们先构造一个从1到n的数组nums:

index 0 1 2
nums 1 2 3

然后我们根据观察可以发现,首位数字2对应的下标index为1,这可以通过 (k - 1) / (n - 1)! = (3 - 1) / (3 - 1)! = 2 / 2 = 1 算出。这里 k - 1 就是 Index 对应的数字,(n - 1)! 就是剩余2位数字的排列情况。
这样找到首位数字2之后,就将其从nums中删除,得到新nums数组:

index 0 1
nums 1 3

接下来,为了找到第二位数字1,我们需要先将k减去首位数字小于2的情况,即 k = k - (n - 1)! * index = 3 - 2 * 1 = 1。这样就排除了其他不正确的情况。此时第二位数字1的index为0,可以通过 (k - 1) / (n - 2)! = (1 - 1) / (3 - 2)! = 0 / 1 = 0 算出。这里 (n - 2)! 代表固定第二位数字后,剩余1位数字的排列情况。然后再将第二位数字1从nums中删除,剩下的数字以此类推。

class Solution {
private:
    vector<int> calFactorial(int n)  // 计算阶乘的函数
    {
        vector<int> fac;
        fac.push_back(1);
        for(int i = 1; i <= n; ++i)
            fac.push_back(i * fac.back());
        return fac;
    }
public:
    string getPermutation(int n, int k) {
        vector<int> nums;
        for(int i = 1; i <= n; ++i)
            nums.push_back(i);
        
        vector<int> fact = calFactorial(n);
        string res;
        for(int i = 0; i < n; ++i)
        {
            int fac = fact[n - i - 1];
            int index = (k - 1) / fac;  // k - 1是关键点
            res.push_back('0' + nums[index]);
            nums.erase(nums.begin() + index);
            k = k - index * fac;
        }
        return res;
    }
};

时间复杂度:O ( N ^ { 2 } ),从nums数组中删除元素,共执行次数为:N + N - 1 + ...... + 1 = N(N - 1) / 2

空间复杂度:O ( N )

相关文章

网友评论

      本文标题:LC60 Permutation Sequence

      本文链接:https://www.haomeiwen.com/subject/iwaffktx.html