以k步为单位的最大排列(R)

时间:2018-05-13 01:39:09

标签: r algorithm permutation greedy

我有一个问题,我想在一个设置中替换2个数字" k" - 这样每次切换时,我得到最大可能的排列并在k-swaps之后打印出来。例如,对于k = 2,对于1步中的集合(1,4,2,5,3,3),我将交换(1,5)以创建(5,4,2,1,3,3)。在步骤2中,我将交换(2,3)以创建(5,4,3,1,3,2)。如果在n<第k点,我们已经有了最大的排列,例如(5,4,3,3,2,1)然后我们停下来。

到目前为止,这就是我所拥有的:

x<-y<-c(1,4,2,5,3,3)
sx<-sort(x,decreasing=TRUE)
if(k>=n){cat(sx)} else{ ### If we have more operations than numbers?
i<-0; k<-2
m<-max(y)
while(i<k){
  if(all(sort(x,decreasing=TRUE)==y)){break}
  i<-i+1
  a<-max(which(y==m))
  while(length(which(y[c(1:a)]<m))==0){
    m<-m-1
    a<-which(y==m) ### Location of the largest number
    if(length(a)==0){
      a<-1
      next
    }
    a<-max(a)
  }
  y[c(min(which(y[c(1:a)]<m)),a)]<-y[c(a,min(which(y[c(1:a)]<m)))]
}
cat(y)
}
5 4 2 1 3 3

本质上,代码找到当前集合的最大值。然后找到此最大数字的最右侧出现。然后找到最左边的数字低于最大数字。然后切换它们。这一直持续到我们执行k步或者我们在k之前具有最大的排列。然后打印出来。

此代码有效,但如果大k超过10 ^ 4位数,则需要太长时间。有没有办法将复杂度降低到R?

中的O(n)

1 个答案:

答案 0 :(得分:0)

这里有一个O(n log n) - 时间算法(O(n)只有比较才有可能,但是你可能对输入数字有所了解。)

对于某些整数[i 2^j, (i+1) 2^j)具有(零索引)边界i, j的排列的每个子数组,将最小值和最大值存储在子数组中(即设置segment tree }结构)。

要查找时间间隔O(log n)中的最大值,请将时间间隔分解为O(log n)个基本时间间隔,并返回最大值的最大值。

要在基本时间间隔O(log n)中找到最右边的最大值,如果其最大值等于目标,则重复下降到右子项,否则下降到左子项。

要在时间间隔O(log n)中找到低于目标数的最左边的数字,请将间隔分解为O(log n)个基本间隔,并找到最小值低于目标的最左边的基本间隔。从这个区间开始,如果最小值低于目标,则反复下降到左侧子项,否则下降到右侧子项。

按照你的例子:

        1,5
  4,5         1,2         3,3
5     4     2     1     3     3

我们刚刚移动5,而4位于正确的位置,因此我们希望数组其余部分的最大值。基本区间为2 13 3。最大值为3。我们检查3 3并发现最大值是在正确的孩子中,最后一直是。

现在我们寻找的最左边的数字小于3。基本区间为2 13 3。我们发现2 1的最小值小于3,因此我们会对其进行检查。 2 1的左侧孩子也是如此,因此2是我们与3交换的内容。

       *1,5*
  4,5        *1,2*       *3,3*
5     4     3     1     3     2

*asterisks*中的聚合可能需要更新(交换值的祖先)。这些中有O(log n)个。我们自下而上。

       *1,5*
  4,5         1,3        *3,3*
5     4     3     1     3     2

        1,5
  4,5         1,3        *3,3*
5     4     3     1     3     2

        1,5
  4,5         1,3         2,3
5     4     3     1     3     2