簡體   English   中英

如何使此代碼運行更快

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

該數組包含數字,並且未排序。 它的長度可能高達100000。我需要計算每個數字右邊的較小數字。

例:

    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

任務:我有100項測試要執行,目標是在12毫秒內完成所有測試。 以下功能是AVL樹實現。 它可以完成工作,但速度不夠快。

它在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);
  }

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

我有第二種方法,它更快但仍然不夠快。 它在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);
}

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

我想了解他們為什么沒有實現目標以及如何改善他們。

這很不錯,但是我不知道這是針對(代碼戰?)的挑戰,因此我無法對其進行測試。 不使用樹木。

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(","));

我只需要一個簡單的鏈表就可以做到:

 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"); 

在具有100000個值的三個四個實現的控制台中進行了快速測試。

  • 您的第一個代碼:〜700-800ms
  • 您的第二個代碼:〜350-400ms
  • 我的代碼:〜15-30ms
  • 詹姆斯代碼:〜25000ms

所有實現都在相同的預生成的100000項數組上進行了測試。

smaller的節點導出Node構造函數可以提高性能,因此第二和第三測試更有可能在15ms而不是30ms處進行測試。 這與JS引擎如何優化代碼有關。 此外,使用0值預填充數組可使代碼加速大約十倍。

但是,對於短數組或具有100個以上不同值的數組,其差異應該較小。

好的,我已經通過一些重構來加快您的代碼的速度。

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;
}

我很想知道他們拋出這個函數需要花費很長時間才能計算出來。 我們正在談論的是12秒而不是12毫秒內的100次計算。 我猜想是大型數組和很多不同的值(浮點數或使用整數的整個范圍,而不僅僅是8位:0 ... 255)。

仍在嘗試不同的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM