java 返回第k小的数_java – 给定n和k,返回第k个置换序列

所以如果我正确地阅读这个问题,你想要找到第k个排列,最好不要使用BigInteger,只要k不够大,不需要一个BigInteger.

如果我们看序列

1 2 3

1 3 2

2 1 3

2 3 1

3 1 2

3 2 1

我们可以重写它,以便每个位置的数字是到目前为止还没有出现的数字列表的索引:

0 0 0

0 1 0

1 0 0

1 1 0

2 0 0

2 1 0

所以例如“2,0”表示从列表“1,3”开始,然后取第三个(因为我们从零索引),这是一个3,然后取第一个剩余的数字“ 1,2“是1,然后是第一个剩余的数字,即”2“.所以它产生“3,1,2”.

要生成这些索引,从右到左,将k除以1!最右边的两个地方,然后2!然后3!然后4!等等,然后用该位置的可能索引的数量模拟结果,最右边为1,最右侧为2等.您不必每次都计算因子,因为您可以保留正在运行的产品.

一旦k除以阶乘为零,你就可以突破循环,所以你只需要计算阶乘,直到大致大小的k乘以k除以阶乘的最后一个地方是非零.如果k太大,则需要切换到BigInteger.

一旦你有了索引,用它来产生排列就是非常简单的.

代码(k从0开始,所以找到第一遍0,不是1):

static public void findPermutation(int n,int k)

{

int[] numbers = new int[n];

int[] indices = new int[n];

// initialise the numbers 1,3...

for (int i = 0; i < n; i++)

numbers[i] = i + 1;

int divisor = 1;

for (int place = 1; place <= n; place++)

{

if((k / divisor) == 0)

break; // all the remaining indices will be zero

// compute the index at that place:

indices[n-place] = (k / divisor) % place;

divisor *= place;

}

// print out the indices:

// System.out.println(Arrays.toString(indices));

// permute the numbers array according to the indices:

for (int i = 0; i < n; i++)

{

int index = indices[i] + i;

// take the element at index and place it at i,moving the rest up

if(index != i)

{

int temp = numbers[index];

for(int j = index; j > i; j--)

numbers[j] = numbers[j-1];

numbers[i] = temp;

}

}

// print out the permutation:

System.out.println(Arrays.toString(numbers));

}

[1,3]

[1,2]

[2,3]

[2,1]

[3,2]

[3,1]

n = 100的10000000次排列:

[1,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,92,98,96,90,91,100,94,97,95,99,93 ]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值