leetcode_060 Permutation Sequence

来源:互联网 发布:倩女幽魂手游mac版 编辑:程序博客网 时间:2024/06/13 12:54

题意分析:1~n组成的序列从小到大排序,按顺序找出k个序列,并输出。

解题思路:

                     对于数值n,排列组合共有n!种排列。

                     第一位每个数组开头的序列有(n-1)!个序列,

                     依此类推,第二位每一个数开头有(n-2)!个序列。

                     因数字不重复,故用sign标记数字是否使用过,data存阶层的数,每次循环找到没有使用的数中第

                     k/data[i]个数就是当前位的数字。

                     其详细过程见程序中注释。

class Solution {public:// 利用库函数实现(超时)     string getPermutation(int n, int k) {        string str = string("123456789").substr(0, n);        for(int i = 1; i <= k-1; i++)            next_permutation(str.begin(), str.end());        return str;    }    // 递归实现(超时)     string getPermutation(int n, int k) {string result;vector<int> nums;        for (int i = 1; i <= n; i++)nums.push_back(i);        for(int i = 1; i <= k-1; i++)            nextPermutation(nums);        for (int i = 0; i < nums.size(); i++)        {        result += nums[i] + '0';}return result;    }        void myswap(int &x, int &y){int t;t = x;x = y;y = x;}void nextPermutation(vector<int> &nums){int n = nums.size();if (n == 1)return;for (int i = n - 2, j = n - 1; i >= 0; i--, j--){//执行第一步,从后向前,找第一个不满足递增的数nums[i] if (nums[i] < nums[j]){int k = n - 1;//执行第二步,从后向前,找第一个比nums[i]大的数nums[k] while (nums[k] <= nums[i])k--;//执行第三步,交换两个数nums[i]和num[k] swap(nums[i], nums[k]);//执行第四步,对nums[i] 后面的数进行翻转reverse(nums.begin() + j, nums.end());return ;}}//当没第一步未找到合适的数,则对整个进行翻转 reverse(nums.begin(), nums.end());}// 上面超时的原因是算法都是逐个求排列,下面利用非逐个求,而是直接构造第k个排列。以n=4,k=17为例,数组src=[1,2,3,...]。// 计算第17个排列的第一个数。首先直到(n-1)!=3!=6,即以1和2开头的排列总共有6*2=12个<17,故第17个排列的第一个数不可能为// 1或者2,6*3>17,故第17个排列第一个数为3。即第17个排列的第一数是原数组(原数组有序)的第m=upper(17/6)=3个数。第一个// 数固定后,从src数组中删除概述,相当于在当前src的基础上求k-(m-1)*(n-1)!=17-2*6=5个排列,在递归求解。string getPermutation(int n, int k){string str = string("123456789").substr(0, n);string result(n, ' ');for (int i = 0; i < n; i++){result[i] = helper(str, k);}return result;}// 以s中字符构造全排列中,返回第k个排列的第一个字符,并删除s中该字符,s中字符递增有序char helper(string &s, int &k){int tmp = factorial(s.size() - 1);int i = (k - 1) / tmp;char res = s[i];s.erase(i, 1);k -= i * tmp;    // 更新kreturn res; }int factorial(int n){int res = 1;for (int i = 2; i <= n; i++)res *= i;return res; }// 上面算法的非递归实现(未超时) string getPermutation(int n, int k){int total = factorial(n);string candidate = string("123456789").substr(0, n);string res(n, ' ');for (int i = 0; i < n; i++)   // 依次计算排列的每个位{total /= (n - i);int index = (k - 1) / total;res[i] = candidate[index];candidate.erase(index, 1);k -= index * total;}return res; }int factorial(int n){int res = 1;for (int i = 2; i <= n; i++){res *= i;}return res;} // 整体思路:先初始化字符串"1,2,...,n",然后从0位开始逐步确定每一位的数字,第i位后面的数字有(n-1-i)!种排法,若假设k<(n-1-i)!,则// 可确定第i位的数字。 string getPermutation(int n, int k){// 初始化字符串"1...n" int Kn = 1;string res(n, '1');for (int i = 2; i <= n; i++){Kn *= i;res[i - 1] = i + '0';}int temp = n;for (int i = 0; i < res.size(); i++){Kn /= temp;for (int j = i + 1; j < n && k > Kn; j++){swap(res[i], res[j]);k -= Kn;if (k == 1)break; }temp--;}return res; }    // 非递归实现(未超时) string getPermutation(int n, int k){int i;int j;int data[10];int sign[10];data[1] = 1;for (i = 2; i <= n; i++){data[i] = data[i - 1] * i;}for (int i = 0; i < 10; i++){sign[i] = 0;}string s = "";i = i - 2;k--;while (i >= 0){int temp = k / data[i];for (j = 1; j < 10; j++){if (sign[j] == 0)temp--;if (temp < 0)break;}sign[j] = 1;s += j + '0';k %= data[i];i--;}return s;}  };


0 0
原创粉丝点击