题目大意:给出n和k,找到1..n这些数组成的有序全排列中的第k个。
首先,n的全排列可以分成n组,每一组由n-1个数组成。
例如 3的全排列,分成三组:
1 2 3 和 1 3 2
2 1 3 和 2 3 1
3 1 2 和 3 2 1
每一组的个数是(n-1)!,每一组的打头的都是i 。第i组以i打头。
先求 x = (k-1) / (n-1)! + 1
比如 n = 3, k = 4.
x = 3/2 + 1 = 2,得到 第四个实际上第二组里面。
y = (k-1)%(n-1)! + 1 = 2,即,要求的东西在第二组的第二个数。
第二组的特征是,以2开头。所以我们找到第2个数,放到string ans的最高位置。
然后,求剩下的数里面的全排列的第y个。 即把2去掉,用1 和 3做全排列,取其中的第2个。
这时候,回到初始的步骤。递归即可。
垃圾的代码,现在脑子懵。。写的代码跟屎一样,完全没有逻辑啊!要优化!!
class Solution {
public:
int factorial(int n) //计算n的阶乘
{
if(n == || n == ) return ;
return n*factorial(n-);
} void back_track(vector<int>&used, string &ans, int n, int cnt, int k) //cnt表示ans里有几个元素。找到第k个。
{
if(cnt == n) return; //所有的都用完了 int fac = factorial(n--cnt); //初始是n-1 int x = (k-)/fac + ; //在第x 个序列 第一个数是第几个
k = (k-)%fac + ; //x序列的第k个 int i,j; i = ; while(used[i]) i ++; //找到第一个没用过的元素
for(j = ; j < x;i++) //这时候x指向的是第1个未使用的元素
{
if(!used[i]) j++; //此时x走过了j-1个元素。
}
while(used[i]) i++; //找到第x个未使用的元素 ans.append(,i + ''); //把这个元素放在头
used[i] = true; //这个元素被使用了
back_track(used, ans, n, cnt + ,k); //用剩下的去构造第k个元素
}
string getPermutation(int n, int k) {
int i;
vector<int> used(n+,false);
string ans;
back_track(used,ans,n,,k);
return ans;
} };