leetcode刷题5——排列系列

本文深入探讨了多种排列相关算法,包括下一个排列、全排列及其变种、排列序列等问题的解决方法。通过具体实例介绍了如何利用回溯法和特殊技巧来求解这些经典问题。

1.下一个排列
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须 原地 修改,只允许使用额外常数空间。
考察知识点:两遍扫描
思路:
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:
    void nextPermutation(vector<int>& nums) {
        int i = nums.size() - 2;
        while (i >= 0 && nums[i] >= nums[i + 1])	i--;
        if (i >= 0)
         {
            int j = nums.size() - 1;
            while (j >= 0 && nums[i] >= nums[j])	j--;
            swap(nums[i], nums[j]);
        }
        reverse(nums.begin() + i + 1, nums.end());
    }
};

2.全排列
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
考察知识点:回溯

class Solution {
public:
    vector<vector<int>> ans;
    vector<vector<int>> permute(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        perm(nums, 0, nums.size() - 1);
        return ans;
    }  
    void perm(vector<int> nums, int left, int right) {
        if (left == right)
        {    
            ans.push_back(nums);
            return;
        }        
        for (int i = left; i <= right; i++) 
        {
            swap(nums[left], nums[i]);
            perm(nums, left + 1, right);
        }
    }
};

3.全排列 II
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
考察知识点:回溯

class Solution {
public:
    vector<vector<int>> ans;
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        perm(nums, 0, nums.size() - 1);
        return ans;
    }  
    void perm(vector<int> nums, int left, int right) {
        if (left == right)
        {    
            ans.push_back(nums);
            return;
        }        
        for (int i = left; i <= right; i++) 
        {
            if (i != left && nums[left] == nums[i]) continue;  
            swap(nums[left], nums[i]);
            perm(nums, left + 1, right);
        }
    }
};

4.排列序列
给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
"123""132""213""231""312"“321”
给定 n 和 k,返回第 k 个排列。

作死解法:(调库函数)

class Solution {
public:
    string getPermutation(int n, int k) {
        string s="";
        for(int i=1;i<=n;++i)
            s+=to_string(i);
        do{
            --k;
            if(k==0)    break;
        }while(next_permutation(s.begin(),s.end()));
        return s;
    }
};

憨憨解法:(回溯所有可能)

class Solution {
public:
    string getPermutation(int n, int k) {
        string s="";
        for(int i=1;i<=n;++i)
            s+=to_string(i);
        perm(s,0,s.size()-1,k);
        return ans[k-1];
    }
     vector<string> ans;
     void perm(string str, int left, int right, int num) {
        if (left == right)
        {
            ans.push_back(str);
            if(ans.size()==num)
                return;
        }
        else
         {
            for (int i = left; i <= right; i++)
            {
                swap(str[left], str[i]);
                perm(str, left + 1, right, num);
            }
        }
    }
};

大佬解法:(逆康托展开)

class Solution {
public:
	string getPermutation(int n, int k) {
		vector<char> chs={'1','2','3','4','5','6','7','8','9'};
		vector<int> factor={1,1,2,6,24,120,720,5040,40320,362880};
		string str="";
		for(--k; n--; k%=factor[n])
		{
			int i=k/factor[n];
			str+=chs[i];
			chs.erase(chs.begin()+i);
		}
		return str;
	}
};
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

给算法爸爸上香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值