【LeetCode】13.Permutation Sequence

题目描述(Medium)

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.

题目链接

https://leetcode.com/problems/permutation-sequence/description/

Example 1:

Input: n = 3, k = 3
Output: "213"

Example 2:

Input: n = 4, k = 9
Output: "2314"

算法分析

康托展开与逆展开

康托展开是一个全排列到一个自然数的双射,因此是可逆的。对于康托展开,对(1,2,3,4,5)可以算出第62个排列组合为34152。由上述的计算过程可以容易的逆推回来,具体过程如下:
用 61 / 4 != 2余13,说明比首位小的数有2个,所以首位为3。
用 13 / 3 != 2余1,说明在第二位之后小于第二位的数有2个,所以第二位为4。
用 1 / 2 != 0余1,说明在第三位之后没有小于第三位的数,所以第三位为1。
用 1 / 1 != 1余0,说明在第二位之后小于第四位的数有1个,所以第四位为5。
最后一位自然就是剩下的数2。
通过以上分析,所求排列组合为 34152。

提交代码:

class Solution {
public:
	string getPermutation(int n, int k) {
		string S(n, '0');
		string result;
		int base = 1;

		for (int i = 1; i < n; ++i)
			base *= i;
		for (int i = 0; i < n; ++i)
			S[i] += i + 1;
		
		--k;
		for (int i = n - 1; i > 0; --i)
		{
			auto iter = next(S.begin(), k / base);
			result.push_back(*iter);
			S.erase(iter);
			k %= base;
			base /= i;
		}

		result.push_back(S[0]);
		return result;
	}
};

测试代码:

// ====================测试代码====================
void Test(const char* testName, int n, int k, string expected)
{
	if (testName != nullptr)
		printf("%s begins: \n", testName);

	Solution s;
	string result = s.getPermutation(n, k);

	if (result == expected)
		printf("passed\n");
	else
		printf("failed\n");

}

int main(int argc, char* argv[])
{

	Test("Test1", 3, 3, "213");
	Test("Test2", 4, 9, "2314");

	return 0;
}

猜你喜欢

转载自blog.csdn.net/ansizhong9191/article/details/82020743