Leetcode 排列相关的题目

31. Next Permutation

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place and use only constant extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.

1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

题目大意:
给定一个排列,找到下一个字典序比他大的排列。如果没有比他大的排列,那么就给出一个字典序最小的排列出来。新的排列,需要使用到给定 排列的所有元素,每个元素只能被使用一次

所谓字典序,是指字符串的比较顺序:先比较第一位,第一位相等再比较第二位····,不相等直接给出谁大谁小。这字典序里面,越优先比较的位 其 位权越大(类似于,我们比较整数大小时,例如4位数和位数,也是从千开始比较,千位最先比较于是它的权重最大 ,为1000)。

例如:
给定 1,3,2 ,那么字典序大的下一个排列应该为2,1,3
给定3,2,1,那么字典序 没有比他大的排列了,于是输出这些元素的字典序最小排列。

思路:

首先,我们不能使用搜索的套路来,一个直观的思路:把整个vector转换为一个大整数,然后让整数不断自增,这样比原排列大的条件满足了。再判断这个序列是否为原来所有元素的一个排列即可。 但是很明显 ,这个复杂度很高的,如果这个vector元素有上百个,这肯定不行。于是我们得使用构造法。

除了无更大排列的情况下,我们既然要把排列改大,那么肯定至少得交换两个元素的位置。而且交换前,后一个元素大于前一个元素,这样交换才能使得排列变大。与此同时,这个交换位置越往后越好,因为改动后面的元素使用排列的序变化的越小。
于是,我们首先可以寻找到应该在那个部位发生交换: 从前往后遍历整个列表,找到最后一个nums[i]>nums[i-1] 的下标 i 出来。这种 i-1 的那个位置就是要变化的。那么 我们应该把 i-1位置上的元素 变成什么呢?i-1 前面的元素肯定是不能动。只能从i开始往后找,找到那个大于nums[i-1] 里面 最小的那个元素即可。这是因为我们要找比当前序列下一个大的,因此,我们对排列序的改动越小越好。最后,既然i-1 位置改了,那么新排列肯定是比原序列大,因为新排列和旧排列[0,i-2] 一样,新的排列第i-1个位置更大。但是我们并不确认此时的新序列就是满足条件的最小的那个, 我们还得把从i开始往后的部分取最小字典序。

例如:1,3,2
可以知道 i=1,即 第i-1 位需要改,那么改成从[3,2]选最小的那个就行。于是首位变成了2,原序列变成了2,3,1,新序列知道第i-1 位大于原来的,i-1 位后面无论怎么排都是比原排列大,再从i=1开始,往后排序即可。

代码:

class Solution {
public:
	void nextPermutation(vector<int>& nums) {
		int n = nums.size();
		if (n <= 1)
		{
			return;
		}
		int change = 0;
		for (int i = 1; i <n; i++)
		{
			if (nums[i]>nums[i - 1])
			{
				change = i;
			}
		}
		if (change == 0)
			//已经是最大的了
		{
			vector<int> tmp;
			for (int i = 0; i <n; i++)
			{
				tmp.push_back(nums[i]);
			}
			for (int i = 0; i <n; i++)
			{
				nums[i] = tmp[n - 1 - i];
			}
		}
		else
		{
			int index = change;
			int minx = nums[change];
			change -= 1;
			for (int i=index ; i < n; i++)
			{
				if (nums[i]>nums[change] && nums[i] < minx)
				{
					minx = nums[i];
					index = i;
				}
			}
			int tmp = nums[change];
			nums[change] = nums[index];
			nums[index] = tmp;
			//change后面 排序
			change++;
			vector<int> ::iterator it = nums.begin();
			minx = 0;
			for (; it != nums.end(); it++)
			{
				if (minx == change) break;
				minx++;
			}
			sort(it, nums.end());
		}
	}
};

结果:
Runtime: 8 ms, faster than 74.82% of C++ online submissions for Next Permutation.
Memory Usage: 8.7 MB, less than 75.27% of C++ online submissions for Next Permutation.

优化一下:把排序开始的迭代器和后面满足条件的最小数字一并在首次遍历中找到:

class Solution {
public:
	void nextPermutation(vector<int>& nums) {
		int n = nums.size();
		if (n <= 1)
		{
			return;
		}
		int change = 1;
		vector<int> ::iterator it = nums.begin(),cit=nums.begin()+1;
		int index = change;
		int minx = nums[index];
		for (int i = 1; i <n; i++)
		{
			if (nums[i]>nums[i - 1])
			{
				index=change = i;
				it = cit;
				minx = nums[index];
			}
			if (nums[i] > nums[change - 1] && nums[i] < minx)
			{
				minx = nums[i];
				index = i;
			}
			cit++;
		}
		if (change == 0)
			//已经是最大的了
		{
			int left = 0, right = n - 1;
			while (left<right)
			{
				int tmp = nums[left];
				nums[left] = nums[right];
				nums[right] = tmp;
				left++;
				right--;
			}
		}
		else
		{
			change -= 1;
			int tmp = nums[change];
			nums[change] = nums[index];
			nums[index] = tmp;
			//change后面 排序
			sort(it, nums.end());
		}
	}
};

结果:
Runtime: 4 ms, faster than 98.80% of C++ online submissions for Next Permutation.
Memory Usage: 8.7 MB, less than 84.95% of C++ online submissions for Next Permutation.

知道了这个解法,那么所有求有几个不同的排列、第几个不同的排列就都可以很好做了。
求有几上不同的排列:从最小的开始迭代的找一下更大的,直到没有更大的停止。
求第几个不同的排列:从最小的开始迭代的找下一个更大的,直到找到所需要的那个为止。

47. Permutations II

Given a collection of numbers that might contain duplicates, return all possible unique permutations.

Example:

Input: [1,1,2]
Output:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
输出所有不同的排列,从最小开始迭代找一个更大的,直到找齐。

class Solution {
public:
	bool nextPermute(vector<int> & nums)
	{
		int n = nums.size();
		int change = 0;
		for (int i = 1; i < n; i++)
		{
			if (nums[i] > nums[i - 1])
			{
				change = i;
			}
		}
		if (change == 0)
		{
			return false;
		}
		else
		{
			change--;
			int minx = nums[change + 1];
			int index = change + 1;
			for (int j = change + 1; j < n; j++)
			{
				if (nums[j] > nums[change] && nums[j] < minx)
				{
					index = j;
					minx = nums[j];
				}
			}
			swap(nums[change], nums[index]);
			vector<int>::iterator it = nums.begin();
			change++;
			for (int i = 0; i < n; i++)
			{
				if (i == change)
				{
					break;
				}
				it++;
			}
			sort(it, nums.end());
			return true;
		}
	}
	vector<vector<int>> permuteUnique(vector<int>& nums) {
		sort(nums.begin(), nums.end());
		vector<vector <int> > rst;
		rst.push_back(nums);
		while (nextPermute(nums)==true)
		{
			rst.push_back(nums);
		}
		return rst;
	}
};

60. Permutation Sequence

The set [1,2,3,…,n] contains a total of n! unique permutations.

By listing and labeling all of the permutations in order, we get the following sequence for n = 3:

"123"
"132"
"213"
"231"
"312"
"321"

Given n and k, return the kth permutation sequence.

Note:

Given n will be between 1 and 9 inclusive.
Given k will be between 1 and n! inclusive.
Example 1:

Input: n = 3, k = 3
Output: “213”
Example 2:

Input: n = 4, k = 9
Output: “2314”

问题: 找第几大的排列
解法:
从最小的排列开始遍历直到找到所需要的。

class Solution {
public:
	bool nextPermute(vector<int> & nums)
	{
		int n = nums.size();
		int change = 0;
		for (int i = 1; i < n; i++)
		{
			if (nums[i] > nums[i - 1])
			{
				change = i;
			}
		}
		if (change == 0)
		{
            sort(nums.begin(), nums.end());
			return false;
		}
		else
		{
			change--;
			int minx = nums[change + 1];
			int index = change + 1;
			for (int j = change + 1; j < n; j++)
			{
				if (nums[j] > nums[change] && nums[j] < minx)
				{
					index = j;
					minx = nums[j];
				}
			}
			swap(nums[change], nums[index]);
			vector<int>::iterator it = nums.begin();
			change++;
			for (int i = 0; i < n; i++)
			{
				if (i == change)
				{
					break;
				}
				it++;
			}
			sort(it, nums.end());
			return true;
		}
	}
	vector<int> permuteUnique(vector<int>& nums,int k) {
		sort(nums.begin(), nums.end());
		int cnt = 1;
		while (nextPermute(nums) == true)
		{
			cnt++;
			if (cnt == k)
			{
				break;
			}
		}
		return nums;
	}
	string getPermutation(int n, int k)
	{
		vector<int> nums;
		for (int i = 1; i <= n; i++)
		{
			nums.push_back(i);
		}
		auto permutate = permuteUnique(nums, k);
		string rst;
		for (int i = 0; i < permutate.size(); i++)
		{
			rst.append(1,'0' + permutate[i]);
		}
		return rst;
	}
};
发布了307 篇原创文章 · 获赞 268 · 访问量 56万+

猜你喜欢

转载自blog.csdn.net/jmh1996/article/details/100550615