题目大意:给出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 == 1 || n == 0) return 1; return n*factorial(n-1); } 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-1-cnt); //初始是n-1 int x = (k-1)/fac + 1; //在第x 个序列 第一个数是第几个 k = (k-1)%fac + 1; //x序列的第k个 int i,j; i = 1; while(used[i]) i ++; //找到第一个没用过的元素 for(j = 1; j < x;i++) //这时候x指向的是第1个未使用的元素 { if(!used[i]) j++; //此时x走过了j-1个元素。 } while(used[i]) i++; //找到第x个未使用的元素 ans.append(1,i + '0'); //把这个元素放在头 used[i] = true; //这个元素被使用了 back_track(used, ans, n, cnt + 1,k); //用剩下的去构造第k个元素 } string getPermutation(int n, int k) { int i; vector<int> used(n+1,false); string ans; back_track(used,ans,n,0,k); return ans; } };