简体   繁体   English

如何使此代码运行更快

[英]How can I make this code to run faster

The array contains digits and it is unsorted. 该数组包含数字,并且未排序。 Its length could be as big as 100000. I need to count the smaller numbers to the right of each digit. 它的长度可能高达100000。我需要计算每个数字右边的较小数字。

Example: 例:

    100, 10, 10, 10, 10]should return 4, 0, 0, 0, 0

    1, 2, 3             should return 0, 0, 0

    1, 2, 0             should return 1, 1, 0

    1, 2, 1             should return 0, 1, 0

Task: I have 100 tests to perform and the goal is to do them all under 12ms. 任务:我有100项测试要执行,目标是在12毫秒内完成所有测试。 The following function is an AVL Tree implementation. 以下功能是AVL树实现。 It gets the job done but not fast enough. 它可以完成工作,但速度不够快。

It performs 48 out of 100 in 12s. 它在12秒内完成100中的48个。

=============== ===============

function smaller(arr) {
  function TreeNode(key) {
    this.key    = key;
    this.size   = 1;
    this.height = 1;
    this.left   = null;
    this.right  = null;
    this.count  = 1;
  }
  var size        = (node) => node == null ? 0 : node.size + node.count - 1;
  var height      = (node) => node == null ? 0 : node.height;
  var getBalance  = (node) => node == null ? 0 : height(node.left) - height(node.right);

  var rotateRight = function(root) {
    var newRoot      = root.left;
    var rightSubTree = newRoot.right;
    newRoot.right    = root;
    root.left        = rightSubTree;
    root.height      = Math.max(height(root.left), height(root.right)) + 1;
    newRoot.height   = Math.max(height(newRoot.left), height(newRoot.right)) + 1;
    root.size        = size(root.left) + size(root.right) + 1;
    newRoot.size     = size(newRoot.left) + size(newRoot.right) + 1;
    return newRoot;
  }
  var rotateLeft = function(root) {
    var newRoot     = root.right;
    var leftSubTree = newRoot.left;
    newRoot.left    = root;
    root.right      = leftSubTree;
    root.height     = Math.max(height(root.left), height(root.right)) + 1;
    newRoot.height  = Math.max(height(newRoot.left), height(newRoot.right)) + 1;
    root.size       = size(root.left) + size(root.right) + 1;
    newRoot.size    = size(newRoot.left) + size(newRoot.right) + 1;
    return newRoot;
  }
  var insertIntoAVL = function(node, key, count, index) {
    if(node == null)return new TreeNode(key);
    if(key  <  node.key){node.left    = insertIntoAVL(node.left, key, count, index);}
    if(key  == node.key){count[index] = count[index] + size(node.left); node.count++; return node;}
    if(key  >  node.key){node.right   = insertIntoAVL(node.right, key, count, index); count[index] = count[index] + size(node.left) + node.count;}
    node.height = Math.max(height(node.left), height(node.right)) + 1;
    node.size   = size(node.left) + size(node.right) + 1;
    var balance = getBalance(node);
    if(balance >  1 && key < node.left.key ){return rotateRight(node);}
    if(balance < -1 && key > node.right.key){return rotateLeft(node);}
    if(balance >  1 && key > node.left.key ){node.left = rotateLeft(node.left); return rotateRight(node);}
    if(balance < -1 && key < node.right.key){node.right = rotateRight(node.right); return rotateLeft(node);}
    return node;
  }
  var countSmallerOnRight = function( arr ) {
    var result = new Array(arr.length).fill(0);
    var root   = null;
    for (var i = arr.length; i--;){root = insertIntoAVL(root, arr[i], result, i);}
    return result;
  }
  return countSmallerOnRight(arr);
  }

================= =================

I have a second approach which is faster but still not fast enough. 我有第二种方法,它更快但仍然不够快。 It performs 84 out of 100 in 12ms; 它在12ms内执行100分中的84分;

================= =================

function smaller(arr) {
  function BSTNode(val, count) {
    this.dup   = 1;
    this.left  = null;
    this.right = null;
    this.val   = val;
    this.count = count;
  }
  var countSmaller = arr => {
    var result = [];
    var root   = null;
    for (var i = arr.length; i--;){root = insert(root, arr[i], result, 0, i);}
    return result;
  }
  var insert = (root, num, result, sum, i) => {
    if (root == null) {
      root = new BSTNode(num, 0);
      result[i] = sum;
      return root;
    } else if (root.val == num) {
      root.dup++;
      result[i] = sum + root.count;
      return root;
    } else if (root.val > num) {
      root.count++;
      root.left = insert(root.left, num, result, sum, i);
    } else {
      root.right = insert(root.right, num, result, sum + root.count + root.dup, i);
    }
    return root;
  }
  return countSmaller(arr);
}

================= =================

I would like to understand why they don't achieve the goal and how can I improve them. 我想了解他们为什么没有实现目标以及如何改善他们。

This is decent, but I don't know what (codewars?) challenge this is for so I can't test it. 这很不错,但是我不知道这是针对(代码战?)的挑战,因此我无法对其进行测试。 Doesn't use trees. 不使用树木。

function smaller(arr) {
    var out = [0];
    var len = arr.length;
    for (var i=len - 2; i >= 0; i--) {
      var c = 0;
      for (var j = i + 1; j < len; j++) {
        if (arr[i] == arr[j]) {
          c += out[j - i - 1];
          break;
        } else if (arr[i] > arr[j]) {
          c++;
        }
      }
      out.unshift(c);
    }
    return out;
}
var testArr = [1,5,2,7,44,878,1,22,999,222,1,1,1,1,1,1,1,1,1,1,1,1,1];
alert(smaller(testArr).join(","));

I can do it without a tree, just with a simple Linked List: 我只需要一个简单的链表就可以做到:

 function Node(value, next){ this.value = value; this.next = next; this.count = 1; } function smaller(array){ return array.reduceRight(function(root, value, i){ var count = 0; for(var prev = root, node; (node = prev.next) && node.value < value; prev = node) count += node.count; root.counts[i] = count; if(node && node.value === value){ node.count++; }else{ prev.next = new Node(value, prev.next); } return root; }, { next: null, counts: Array(array.length).fill(0) }).counts; } console.log("100, 10, 10, 10, 10 -> " + smaller([100, 10, 10, 10, 10])); console.log("1, 2, 3 -> " + smaller([1, 2, 3])); console.log("1, 2, 0 -> " + smaller([1, 2, 0])); console.log("1, 2, 1 -> " + smaller([1, 2, 1])); var sampleData = Array.from({length: 100000}, () => 0|(Math.random() * 100)); console.time("100000 items"); smaller(sampleData); console.timeEnd("100000 items"); 

Did a quick test in the console of the three four implementations with 100000 Values. 在具有100000个值的三个四个实现的控制台中进行了快速测试。

  • your first code: ~700-800ms 您的第一个代码:〜700-800ms
  • your second code: ~350-400ms 您的第二个代码:〜350-400ms
  • my code: ~15-30ms 我的代码:〜15-30ms
  • James' code: ~25000ms 詹姆斯代码:〜25000ms

All implementations tested on the same pregenerated Array of 100000 Items. 所有实现都在相同的预生成的100000项数组上进行了测试。

Exporting the Node constructor out of smaller increases the performance so that the 2nd and 3rd test is more likely at 15ms than at 30ms. smaller的节点导出Node构造函数可以提高性能,因此第二和第三测试更有可能在15ms而不是30ms处进行测试。 This has to do with how the JS Engine can optimize the code. 这与JS引擎如何优化代码有关。 Also prefilling the Array with 0 values sped up the code about tenfold. 此外,使用0值预填充数组可使代码加速大约十倍。

But the differences should be smaller for short Arrays or Arrays with more than 100 different values. 但是,对于短数组或具有100个以上不同值的数组,其差异应该较小。

OK, I've got your code to speed by doing some refactoring. 好的,我已经通过一些重构来加快您的代码的速度。

function BSTNode(val) {
    this.dup   = 1;
    this.left  = null;
    this.right = null;
    this.val   = val;
    this.count = 0;
}

var insert = (root, num, result, sum, i) => {
    if (root === null) {
        result[i] = sum;
        return new BSTNode(num);
    }

    if (root.val === num) {
        root.dup++;
        result[i] = sum + root.count;
    } else if (root.val > num) {
        root.count++;
        root.left = insert(root.left, num, result, sum, i);
    } else {
        root.right = insert(root.right, num, result, sum + root.count + root.dup, i);
    }
    return root;
}

function smaller(arr) {
    var result = Array(arr.length).fill(0);
    var root   = null;
    for (var i = arr.length; i--;)
        root = insert(root, arr[i], result, 0, i);
    return result;
}

I'd be curious to know that they throw at this function that it takes that long to compute. 我很想知道他们抛出这个函数需要花费很长时间才能计算出来。 We're talking about 100 computations in 12 Seconds not 12ms. 我们正在谈论的是12秒而不是12毫秒内的100次计算。 I'd guess big Arrays and lots of different values (either floats or using the whole range of ints, not just like 8 bit: 0 ... 255). 我猜想是大型数组和很多不同的值(浮点数或使用整数的整个范围,而不仅仅是8位:0 ... 255)。

Still trying different approaches. 仍在尝试不同的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM