您的位置:首页 > 产品设计 > UI/UE

leetcode_060 Permutation Sequence

2016-03-26 21:05 429 查看
题意分析: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;    // 更新k
return 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;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: