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

2024-05-11

你如何对给定的数组进行排序arr in-place给定目标索引数组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) 额外空间内解决这个问题?

你能证明你的算法有效吗?


Note:这个问题看起来类似于this one https://stackoverflow.com/q/37460524/247243,但这里变异了ind被允许。


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

你的算法中发生的事情是这样的:

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,本例中没有发生这种情况。

您的算法缺少的是一个贯穿索引子循环的内部循环。尝试更换if by while in 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循环确保您检查每个可能的循环。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在给定目标索引数组的情况下对数组进行就地排序? 的相关文章

随机推荐