Javascript 如何在给定目标索引数组的情况下对数组进行就地排序?
在给定目标索引ind数组的情况下,如何对给定数组arr进行排序 例如:Javascript 如何在给定目标索引数组的情况下对数组进行就地排序?,javascript,arrays,algorithm,sorting,Javascript,Arrays,Algorithm,Sorting,在给定目标索引ind数组的情况下,如何对给定数组arr进行排序 例如: 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,
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]);
}
}
}
你会如何在时间和空间上解决这个问题
你能证明你的算法有效吗
注意:这个问题看起来类似于,但这里允许改变ind
你将如何按时解决这个问题
通过简单地使用一个临时数组并迭代数组两次,您可以将其简化为On
如果您对以较低复杂性的方法实现这一点感到满意,那么有一种方法: 创建一个长度等于arr length且对象为空的新数组 按照ind[i]的索引拼接新数组,移除1个对象,并将其替换为arr[i] 使旧的阵列与新阵列相等 window.onload=函数{ "严格使用",; var arr=[A,B,C,D,E,F]; var ind=[4,0,3,2,1,5]; var-temp=[]; 对于变量i=0;i
function createArray(arr, ind) {
var result = [];
for (var i = 0, len = arr.length; i < len; i++) {
result.push(arr[ind[i]]);
}
return result;
}
关于类似的问题有很多讨论 不同之处在于,在原始问题中,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;
}
}
}
}
它仍然是O1空间,但它会进行冗余检查,并且可能比上一个更复杂。我建议交换,直到达到相同的索引,然后获取下一个外部索引 函数swapar,i,k{ var-temp=arr[i]; arr[i]=arr[k]; arr[k]=温度; } 函数重排{ var i=阵列长度; 而我——{ 而ind[i]!==i{ 斯瓦帕尔,我,我; 斯瓦平德,i,ind[i]; } } } var arr=[A,B,C,D,E,F]; var ind=[4,0,5,2,1,3]; 重组arr,ind; console.logarr;//=>[B、E、D、F、A、C] arr=[A,B,C,D]; ind=[2,3,1,0]; 重组arr,ind;
console.logarr;//=>[D,C,A,B] 该算法失败,因为它在列表的索引上只有一个循环 在您的算法中发生的是:
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替换为:
注意复杂性:虽然这是一个双循环,但复杂性不会改变,因为在每次交换时,一个元素被正确放置,每个元素在循环中最多读取两次一次,在for循环中读取一次
证明说明:我不会在这里对这个算法进行完整的证明,但我可以给出线索。如果ind是一个置换,那么所有元素都属于闭置换子循环。while循环确保您迭代整个周期,for循环确保您检查每个可能的周期。旋转周期比使用交换更快一些。C例如:
// 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;
}
}
对不起,我忘了提到允许的额外空间是O1。@MishaMoroshko对不起,我不明白额外空间的含义。你为什么问同样的问题?你没有在厨房里做饭吗?@trincot如果你仔细阅读,你会发现你链接的其他问题中的要求略有不同。我在问题的末尾添加了一个注释来说明问题。虽然这个代码片段可以解决这个问题,但它确实有助于提高文章的质量。请记住,您将在将来回答读者的问题,这些人可能不知道您的代码建议的原因。还请尽量不要用解释性注释挤满你的代码,这会降低代码和解释的可读性!对我来说似乎是正确的。使用索引数组将元素/周期标记为正在处理,因此可以跳过这些元素/周期,从而将不可变输入的复杂性从On^2降低到最佳On。
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 ]
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]);
}
}
}
// 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;
}
}