2017-04-19 4 views
0

배열에 숫자가 포함되어 있으며 정렬되지 않습니다. 그 길이는 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 개 시험이 있고 목표는 그들에게 모두에서 12ms을하는 것입니다. 다음 함수는 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); 
} 

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

I 왜 그들이 목표를 달성하지 못하고 어떻게 향상시킬 수 있는지 이해하고 싶습니다.

+4

이것은 codereview – mplungjan

+0

에 속합니다. 빠른 컴퓨터에서 실행하십시오. – destoryer

답변

0

그래, 몇 가지 리팩토링을 통해 속도를 향상시킬 코드를 얻었습니다.

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

저는이 기능을 사용하여 계산 시간이 오래 걸린다는 것을 알고 싶습니다. 우리는 12ms가 아니라 12 초 만에 100 회의 계산을 말합니다. 큰 배열과 많은 다른 값을 추측 할 수 있습니다 (8 비트 : 0 ... 255와 같이 float 또는 int의 전체 범위 사용).

여전히 다른 접근 방식을 시도하고 있습니다.

+0

대단히 감사합니다. 솔직히 생각하지 않았습니다. 그러한 작은 변화가 차이를 가져 왔을 것입니다. –

+0

'small'에서'BSTNode'와'insert'를 추출하여 얻을 수있는 주요 개선 사항은'smaller' 호출마다 새로운 Class와 함수를 생성하지 않기 때문에 엔진은 항상 모든 것을 최적화 할 수 있습니다. 같은 종류. 그리고'result' 배열을 적절한 크기로 초기화하고 0으로 채우면 엔진은 배열의 크기를 조정할 필요가 없으며 정의되지 않은 속성/인덱스에 액세스 할 필요가 없으며 모든 값 는 int이며, 내부적으로 배열 이 더 빠르고 메모리 효율이 높도록 최적화 할 수 있습니다. – Thomas

0

이것은 괜찮습니다. 그러나 나는 (코드 워드?) 이것이 무엇인지를 알지 못해서 테스트 할 수 없습니다. 나무를 사용하지 않습니다.

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

https://www.codewars.com/kata/how-many-are-smaller-than-me-ii/train/javascript –

0

난 그냥 간단한 연결리스트로, 나무없이 작업을 수행 할 수 있습니다

function Node(value, next){ 
 
\t this.value = value; 
 
\t this.next = next; 
 
\t this.count = 1; 
 
} 
 

 
function smaller(array){ 
 
\t return array.reduceRight(function(root, value, i){ 
 
\t \t var count = 0; 
 
\t \t for(var prev = root, node; (node = prev.next) && node.value < value; prev = node) 
 
\t \t \t count += node.count; 
 
\t \t root.counts[i] = count; 
 
\t \t 
 
\t \t if(node && node.value === value){ 
 
\t \t \t node.count++; 
 
\t \t }else{ 
 
\t \t \t prev.next = new Node(value, prev.next); 
 
\t \t } 
 
\t \t 
 
\t \t return root; 
 
\t }, { 
 
\t \t next: null, 
 
\t \t counts: Array(array.length).fill(0) 
 
\t }).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 : ~

을 25000ms : ~이

  • 제임스 '코드 15-30ms : ~하는
  • 내 코드를 350-400ms 모든 구현은 동일한 사전 생성 된 100000 개 항목의 배열에서 테스트되었습니다.

    노드 생성자를 smaller 외부로 내 보내면 성능이 향상되므로 두 번째 및 세 번째 테스트가 30ms보다 15ms에 더 많이 발생합니다. 이것은 JS 엔진이 코드를 최적화 할 수있는 방법과 관련이 있습니다. 또한 배열을 0 값으로 채우면 10 배 정도의 코드가 빨라졌습니다.

    그러나 100 개가 넘는 다른 값을 가진 짧은 배열이나 배열의 차이는 작아야합니다.

  • +0

    O (n^2)보다 빠른 것이 필요합니다. 당신은 스스로 exercice를 할 수 있습니다 : https://www.codewars.com/kata/how-many-are-smaller-than-me-ii/train/javascript –