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

Permutation Sequence

2016-05-13 09:08 260 查看
【题目】



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 (ie, for n = 3):

1. “123”

2. “132”

3. “213”

4. “231”

5. “312”

6. “321”

Given n and k, return the kth permutation sequence. Note: Given n will be between 1 and 9 inclusive.

【题意】:按照字典顺序的思想,求出n个数的全排列情况中第k个排列,最后返回形式为字符串。

【解析】

可以一个一个的按次序求排列即利用之前的Next Permutation。

public class Solution {
public String getPermutation(int n, int k) {
// 初始化起始数组
char[] init = new char
;
for (int i = 0; i < n; i++) {
seq[i] = (char) ('0' + i + 1);
}

// 利用nextPermutation找到第k个
for (int i = 1; i < k; i++) {
nextPermutation(init );
}

return String.valueOf(init );
}

public void nextPermutation(char[] init) {
// find the last adjacent two element that is in ascending order
int i = init.length - 1;
while (i > 0 && init[i - 1] >= init[i]) {
i--;
}

if (i == 0) return;

int j = init.length - 1;
while (j >= i && init[i - 1] >= init[j]) {
j--;
}

char tmp = init[i - 1];
init[i - 1] = init[j];
init[j] = tmp;

int l = i;
int r = init.length - 1;
while (l < r) {
tmp = init[l];
init[l] = init[r];
init[r] = tmp;
l++;
r--;
}
}
}


第二种:数学解法

在n!个排列中,第一位的元素总是(n-1)!一组出现的,也就说如果p = k / (n-1)!,那么排列的最开始一个元素一定是nums[p]。
别人的:

1. 能否直接算出集合{1, 2, ..., m}的第n个排列?
设某个集合{a1, a2, ..., am}(a1<a2<...<am)构成的某种序列pn,基于以上分析易证得:若as<at,那么将as作为第1个元素的所有序列一定都小于at作为第1个元素的任意序列。同理可证得:第1个元素确定后,剩下的元素中若as'<at',那么将as'作为第2个元素的所有序列一定都小于作为第2个元素的任意序列。例如4个数的集合{2,
3, 4, 6}构成的序列中,以3作为第1个元素的序列一定小于以4或6作为第1个元素的序列;3作为第1个元素的前题下,2作为第2个元素的序列一定小于以4或6作为第2个元素的序列。
推广可知,在确定前i(i<n)个元素后,在剩下的m-i=s个元素的集合{aq1, aq2, ..., aq3}(aq1<aq2<...<aqm)中,以aqj作为第i+1个元素的序列一定小于以aqj+1作为第i+1个元素的序列。由此可知:在确定前i个元素后,一共可生成s!种连续大小的序列。
根据以上分析,对于给定的n(必有n<=m!)可以从第1位开始向右逐位地确定每一位元素。在第1位不变的前题下,后面m-1位一共可以生成(m-1)!中连续大小的序列。若n>(m-1)!,则第1位不会是a1,n中可以容纳x个(m-1)!即代表第1位是ax。在确定第1位后,将第1位从原集合中删除,得到新的集合{aq1, aq2, ..., aq3}(aq1<aq2<...<aqm),然后令n1=n-x(m-1)!,求这m-1个数中生成的第n1个序列的第1位。
举例说明:如7个数的集合为{1, 2, 3, 4, 5, 6, 7},要求出第n=1654个排列。
(1654 / 6!)取整得2,确定第1位为3,剩下的6个数{1, 2, 4, 5, 6, 7},求第1654 % 6!=214个序列;
(214 / 5!)取整得1,确定第2位为2,剩下5个数{1, 4, 5, 6, 7},求第214 % 5!=94个序列;
(94 / 4!)取整得3,确定第3位为6,剩下4个数{1, 4, 5, 7},求第94 % 4!=22个序列;
(22 / 3!)取整得3,确定第4位为7,剩下3个数{1, 4, 5},求第22 % 3!=4个序列;
(4 / 2!)得2,确定第5为5,剩下2个数{1, 4};由于4 % 2!=0,故第6位和第7位为增序<1 4>;
因此所有排列为:3267514。
1:

public String getPermutation(int n, int k) {
int []num = new int
;
int permCount = 1;
for(int i=0;i<n;i++){
num[i] = i+1;
permCount*=(i+1);
}
k--;
StringBuilder target = new StringBuilder();
for(int i=0;i<n;i++){
permCount = permCount/(n-i);
int choosed = k/permCount;
target.append(num[choosed]);
for(int j=choosed;j<n-i-1;j++){
num[j] = num[j+1];
}
k = k%permCount;
}
return target.toString();
}


2:加了额外空间

public class Solution {
public String getPermutation(int n, int k) {
int data[]=new int[10];
boolean visited[]=new boolean[10];
data[0]=data[1]=1;
ArrayList<Integer> list=new ArrayList<Integer>();
for(int i=1;i<=n;i++)
{
data[i]=data[i-1]*(i);
list.add(i);
}
String result="";
k--;
for(int i=n-1;i>=0;i--)
{
int cur=k/data[i];
int j=1;
for(;j<9;j++)     //从数组中 针对未访问过的元素visited[]=false  找第cur个,找到的为j
{
if(visited[j]==false)
cur--;
if(cur<0)
break;
}
visited[j]=true;
result+=(j);
k=k%data[i];
}
return result;
}

}


给定一种排列,如何算出这是第几个排列呢?
和前一个问题的推导过程相反。例如3267514:
后6位的全排列为6!,3为{1, 2, 3 ,4 , 5, 6, 7}中第2个元素(从0开始计数),故2*720=1440;
后5位的全排列为5!,2为{1, 2, 4, 5, 6, 7}中第1个元素,故1*5!=120;
后4位的全排列为4!,6为{1, 4, 5, 6, 7}中第3个元素,故3*4!=72;
后3位的全排列为3!,7为{1, 4, 5, 7}中第3个元素,故3*3!=18;
后2位的全排列为2!,5为{1, 4, 5}中第2个元素,故2*2!=4;
最后2位为增序,因此计数0,求和得:1440+120+72+18+4=1654
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: