如何有效地给出两个n元组,如何实现/构造以下排列?

时间:2011-11-16 02:08:19

标签: python

我正在研究排队论,我经常会遇到以下情况。

设x,y都是非负整数的n元组(描述n个队列的长度)。另外,x和y各自具有称为“主要队列”的区别队列。例如,

x = [3,6,1,9,5,2],x'= 1

y = [6,1,5,9,5,5],y'= 5

(根据Python术语,我计算队列0-5。)

如何有效地在{0,1,...,5}上实现/构造以下排列f?

  1. 首先设置f(x')= y'。所以这里f(1)= 5。
  2. 然后为任何i设置f(i)= i,使得x [i] == y [i]。显然,没有必要考虑指数x'和y'。所以这里f(3)= 3(长度9)和f(4)= 4(长度均为5)。
  3. 现在有相同大小的队列在x和y中未配对。所以这里的x是{0,2,5},而y是{0,1,2}。
  4. 将这些从1到s排名,其中s是集合的通用大小,长度为1 ==最低等级==最短队列和s ==最高等级==最长队列。所以这里,s = 3,并且在x rank(0)= 1,rank(2)= 3和rank(5)= 2,并且在y rank(0)= 1,rank(1)= 3,rank( 2)= 2.如果存在平局,请将具有较大索引的队列命名为较高级别。
  5. 按等级排列这些队列。所以这里f(0)= 0,f(2)= 1,f(5)= 2。
  6. 这应该给出排列[0,5,1,3,4,2]。

    我的解决方案包括多次跟踪x和y上的索引和循环,并且非常低效。 (在我的申请中粗略地看n> = 1,000,000。)

    非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

由于您必须进行排名,因此无法获得线性并且需要排序。所以它看起来非常简单。你只需要遍历n元组就可以在O(1)和O(n)中做1.同时,您可以构造x和y的副本,只包含那些留给3的那些副本但不包含该值,而是使用值的元组及其原始索引。

在你的例子中,x-with-tuples-left将是[[3,0],[1,2],[2,5]]和y-with-tuples-left将是[[6,0] ],[1,1],[5,2]。

然后只排序x-with-tuples-left和y-with-tuples-left(它将是O(n.log n)),并从相应元组的第二个元素中读取排列。

在你的例子中,排序x-with -...将是[[1,2],[2,5],[3,0]]并且y-with -...排序为[[1] ,1],[5,2],[6,0]。现在,你很好地从第二个元素看到5. f(2)= 1,f(5)= 2,f(0)= 0。

编辑:在Javascript中包含O(n + L):

function qperm (x, y, xprime, yprime) {
  var i;
  var n = x.length;
  var qperm = new Array(n);
  var countsx = [], countsy = []; // same as new Array()
  qperm[xprime] = yprime; // doing 1.

  for (i = 0; i < n; ++i) {
    if (x[i] == y[i] && i != xprime && i != yprime) { // doing 2.
      qperm[i] = i; }
    else { // preparing for 4. below
      if (i != xprime) {
        if (countsx[x[i]]) countsx[x[i]]++; else countsx[x[i]] = 1; }
      if (i != yprime) {
        if (countsy[y[i]]) countsy[y[i]]++; else countsy[y[i]] = 1; } }

  // finishing countsx and countsy
  var count, sum;
  for (i = 0, count = 0; i < countsx.length; ++i) {
    if (countsx[i]) {
      sum = count + countsx[i];
      countsx[i] = count;
      count = sum; }
  for (i = 0, count = 0; i < countsy.length; ++i) {
    if (countsy[i]) {
      sum = count + countsy[i];
      countsy[i] = count;
      count = sum; }

  var yranked = new Array(count);      
  for (i = 0; i < n; ++i) {
    if (i != yprime && (x[i] != y[i] || i == xprime)) { // doing 4. for y
      yranked[countsy[y[i]]] = y[i];
      countsy[y[i]]++; } }

  for (i = 0; i < n; ++i) {
    if (i != xprime && (x[i] != y[i] || i == yprime)) { // doing 4. for x and 5. at the same time
      // this was here but was not right: qperm[x[i]] = yranked[countsx[x[i]]];
      qperm[i] = yranked[countsx[x[i]]];
      // this was here but was not right: countsy[y[i]]++; } } }
      countsx[x[i]]++; } }

  return qperm; }

希望这是正确的; - )