防止循环内的循环。如何降低复杂性

时间:2015-08-17 20:52:44

标签: javascript arrays performance time-complexity space-complexity

你有2个阵列 arrA是空的。
arrB充满了东西(它充满了什么并不重要,但假设它很大)。

当用户执行某项操作时,会从arrB中删除该项目,并将该项目放在arrA中。

当用户执行其他操作时,它会从arrA中提取项目并将其放入arrB中。

是否可以在循环内没有循环的情况下执行此操作?

或者把它放在计算机科学术语中:
是否可以用线性(Θ(n))时间/空间复杂度来做到这一点? 现在我的东西至少是Θ(n * k)

(其中n是arrB的长度,k是传递给applyItems的项目数):

var arrA = [], arrB = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];

function addToArray(arrayToAddTo, item){
  if(arrayToAddTo.indexOf(item) === -1){
    arrayToAddTo.push(item);
  }
}

function removeFromArray(arrayToRemoveFrom, item){
  var i = arrayToRemoveFrom.length;
  var temp = [];
  while(i--){
    if(arrayToRemoveFrom[i] !== item){
      temp.push(arrayToRemoveFrom[i]);
    }   
  }
  return temp;
}

function applyItems(arrayOfItems){
  var i = arrayOfItems.length;
  while(i--){
    var current = arrayOfItems[i]
    addToArray(arrA, current);
    arrB = removeFromArray(arrB, current);
  }
}

applyItems([0, 5, 3]);
console.log(arrA);
console.log(arrB);

applyItems有效,但效率不高。

这可以减少时间/空间复杂度吗?

3 个答案:

答案 0 :(得分:1)

根据我的评论:

  

您可以使用比手动循环更快的本机工具。 removeFromArray可以使用indexOf来获取要删除的位置,然后使用splice删除它。此外,您可以使用引用而不是每次都重新创建数组。

进行其他一些优化......

{{1}}

答案 1 :(得分:1)

  

现在我的东西至少是Θ(n * k)

您可以使用O(n+k)的高效查找结构arrayOfItems使其不需要循环,但允许您在O(1)中确定是否应将项目交换到另一个项目中阵列。有了它,只需arrB一次就可以了 或者,如果您对数组进行排序并使用二进制搜索进行查找,那么您将拥有O(log k * (n+k))。但是,如果你的阵列是有限的而且非常小,这几乎不重要。

另外,您应该在indexOf中省略addToArray测试。似乎已确定arrAarrB中都没有项(并且您的算法保持不变),因此在将项目推送到数组之前,您不必检查重复项。

答案 2 :(得分:0)

是。您可以使用splice()

,而不是自己执行删除功能

因此,您可以removeFromArray(arrB, current)代替arrB.splice(i, 1);而不是1。这将从索引i中删除 var i = arrA.indexOf(item) 元素。

您不需要遍历每个元素以检查它是否与您想要的元素匹配 - 只需使用indexOf()即可。所以你可以做类似

的事情
protected void CreateBatch(Func<IBatch, List<Task>> action)
    {
        IBatch batch = Database.CreateBatch();

        List<Task> tasks = action(batch);

        batch.Execute();

        Task.WaitAll(tasks.ToArray());
    }

    protected IEnumerable<T> GetBatch<T, TRedis>(
        IEnumerable<RedisKey> keys, 
        Func<IBatch, RedisKey, Task<TRedis>> invokeBatchOperation, 
        Func<TRedis, T> buildResultItem)
    {
        IBatch batch = Database.CreateBatch();
        List<RedisKey> keyList = keys.ToList();
        List<Task> tasks = new List<Task>(keyList.Count);
        List<T> result = new List<T>(keyList.Count);

        foreach (RedisKey key in keyList)
        {
            Task task = invokeBatchOperation(batch, key).ContinueWith(
                t =>
                    {
                        T item = buildResultItem(t.Result);
                        result.Add(item);
                    });

            tasks.Add(task);
        }

        batch.Execute();
        Task.WaitAll(tasks.ToArray());

        return result;
    }