如何在给定目标索引数组的情况下对数组进行排序?

时间:2016-06-09 11:36:25

标签: javascript arrays algorithm sorting

给定一系列目标索引arr,您如何对给定数组ind 就地进行排序?

例如:

var arr = ["A", "B", "C", "D", "E", "F"];
var ind = [ 4,   0,   5,   2,   1,   3 ];

rearrange(arr, ind);

console.log(arr); // => ["B", "E", "D", "F", "A", "C"]

arr = ["A", "B", "C", "D"];
ind = [ 2,   3,   1,   0 ];

rearrange(arr, ind);

console.log(arr); // => ["D", "C", "A", "B"]

我尝试了以下算法,但在上面的第二个例子中失败了。

function swap(arr, i, k) {
  var temp = arr[i];
  arr[i] = arr[k];
  arr[k] = temp;
}

function rearrange(arr, ind) {
  for (var i = 0, len = arr.length; i < len; i++) {
    if (ind[i] !== i) {
      swap(arr, i, ind[i]);
      swap(ind, i, ind[i]);
    }
  }
}

你如何在O(n)时间和O(1)额外空间中解决这个问题?

您能提供算法有效的证据吗?

注意:此问题与this one类似,但此处允许变更ind

7 个答案:

答案 0 :(得分:7)

算法失败,因为它只有一个循环覆盖列表的索引。

您的算法中会发生以下情况:

i=0 -> ["A", "B", "C", "D"] , [ 2,   3,   1,   0 ]
i=1 -> ["C", "B", "A", "D"] , [ 1,   3,   2,   0 ]
i=2 -> ["C", "D", "A", "B"] , [ 1,   0,   2,   3 ]
i=3 -> ["C", "D", "A", "B"] , [ 1,   0,   2,   3 ]

请注意,第一次交换时,1处于0位置,除非您将其与0交换,否则您不会再次访问它,这在此示例中不会发生。< / p>

您的算法遗漏的是一个内部循环,它贯穿索引的子循环。尝试将if替换为while中的rearrange

function rearrange(arr, ind) {
   for (var i = 0, len = arr.length; i < len; i++) {
      while (ind[i] !== i) {
         swap(arr, i, ind[i]);
         swap(ind, i, ind[i]);
      }
   }
}

关于复杂性的注意事项:虽然这是一个双循环,但复杂性不会改变,因为在每次交换时,一个元素被正确放置,每个元素最多读取两次(一次循环,一旦通过for循环)。

关于证明的说明:我不会在这里完整地证明这个算法,但我可以给出引导。如果ind是排列,那么所有元素都属于闭合的置换子循环。 while循环确保您重复整个周期,for循环可确保您检查每个可能的周期。

答案 1 :(得分:1)

我建议交换,直到达到相同的索引,然后取下一个外部索引。

&#13;
&#13;
function swap(arr, i, k) {
    var temp = arr[i];
    arr[i] = arr[k];
    arr[k] = temp;
}

function rearrange(arr, ind) {
    var i = arr.length;
    while (i--) {
        while (ind[i] !== i) {
            swap(arr, i, ind[i]);
            swap(ind, i, ind[i]);
        }
    }
}

var arr = ["A", "B", "C", "D", "E", "F"];
var ind = [ 4,   0,   5,   2,   1,   3 ];

rearrange(arr, ind);
console.log(arr); // => ["B", "E", "D", "F", "A", "C"]

arr = ["A", "B", "C", "D"];
ind = [ 2,   3,   1,   0 ];

rearrange(arr, ind);
console.log(arr); // => ["D", "C", "A", "B"];
&#13;
&#13;
&#13;

答案 2 :(得分:0)

  

你会在O(n)时间内解决这个问题吗?

只需使用临时数组并迭代数组两次,就可以将其减少到O(n)

function rearrange(arr, ind) 
{
  var temp = [], len = arr.length;
  //first re-arrange in a new array
  for(var counter = 0; counter < len; counter++)
  {
     temp[ind[counter]] = arr[counter];
  }  
  //copy the values as per new indices from temp
  for(var counter = 0; counter < len; counter++)
  {
     arr[counter] = temp[counter];
  }  
}

答案 3 :(得分:0)

如果您对复杂度较低的方法表示满意,那么就有一个:

  • 制作一个长度等于arr长度且空对象
  • 的新数组
  • splice新数组的索引为ind[i],删除1个对象,并将其替换为arr[i]
  • 将旧数组(arr)与新数组
  • 进行均衡

window.onload = function () {
    
    'use strict'; 
	
	var arr = ["A", "B", "C", "D", "E", "F"];
	var ind = [ 4,   0,   3,   2,   1,   5 ];
	var temp = [];

	for (var i = 0; i < arr.length; i++) {
	    temp[i] = '';
	}

	for (var v = 0; v < arr.length; v++) {
	    temp.splice(ind[v], 1, arr[v]);
	}
	
	arr = temp;
	console.log(arr);
};

答案 4 :(得分:0)

我建议您将结果返回到新数组

   function createArray(arr, ind) {
        var result = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            result.push(arr[ind[i]]);
        }
        return result;
    }

这是在O(n)时间

var arr = ["A", "B", "C", "D", "E", "F"];
var ind = [4, 0, 5, 2, 1, 3];
console.log(createArray(arr,ind))

答案 5 :(得分:0)

关于类似问题In-place array reordering?

的讨论很多

不同之处在于原始问题ind[i]是元素arr[i]的必需索引,而在类似问题中i是元素arr[ind[i]]的必需索引

回到原始算法,一个可行的替代方案可能是

function swap(arr, i, k) {
  var temp = arr[i];
  arr[i] = arr[k];
  arr[k] = temp;
}

function rearrange(arr, ind) {
  for (var i = 0, len = arr.length; i < len; i++) {
    if (ind[i] !== i) {
      swap(arr, i, ind[i]);
      swap(ind, i, ind[i]);
      if (ind[i] < i) {
        i = ind[i]-1;
      }
    }
  }
}

它仍然是O(1)空间,但它会进行冗余检查,可能比O(n)更复杂

答案 6 :(得分:0)

“旋转”周期而不是使用交换更快一些。例如:

    // reorder A in place according to sorted indices in I
    // tA is temp value for A
    for(i = 0; i < n; i++){
        if(i != I[i]){
            tA = A[i];
            k = i;
            while(i != (j = I[k])){
                A[k] = A[j];
                I[k] = k;
                k = j;
            }
            A[k] = tA;
            I[k] = k;
        }
    }