javascript hackerranks sherlock和数组性能问题

时间:2016-10-06 16:28:20

标签: javascript arrays algorithm performance

  沃森给了夏洛克一个长度为N的阵列A.然后他问他   确定数组中是否存在元素的总和   左边的元素等于其元素的总和   对。如果左/右没有元素,则总和为   被认为是零。正式地,找到一个,这样,

     

输入格式

     

第一行包含T,即测试用例的数量。对于每个测试   case,第一行包含N,即数组中的元素数   答:每个测试用例的第二行包含N个空格分隔   整数,表示数组A。

     

约束

1<=T<=10
1<=N<=10^5
1<=Ai<=2*10^4
1<=i<=N
     

输出格式

     

对于每个测试用例,如果数组中存在元素,则打印YES,   这样左边元素的总和等于总和   右边的元素;否则打印NO。

     

示例输入

2 
3
 1 2 3

4
 1 2 3 3
     

示例输出

NO 
YES
     

解释

     

对于第一个测试用例,不存在这样的索引。进行第二次测试   情况下,

     

因此指数3满足给定条件。

我在3个测试用例中遇到超时问题

 function check(input) {
    var result = "NO";
    var sum=0;
    input.map(function(data){
        sum=sum+(+data);
    })
    sumLeft=0;
    sumRight=sum-(+input[0]);

    for(var i=1;i<input.length;i++){
        sumLeft=sumLeft+(+input[i-1]);
        sumRight=sumRight-(+input[i])
        if(sumLeft==sumRight)
        {
            console.log("YES");
            return;
        }
    }
    console.log("NO");
}

function processData(input) {
    //Enter your code here
    var lines = input.split("\r\n");
    for (var m = 2; m < lines.length; m = m + 2) {
        check(lines[m].split(" "));
    }
}
process.stdin.resume();
process.stdin.setEncoding("ascii");
_input = "";
process.stdin.on("data", function(input) {
    _input += input;
});
process.stdin.on("end", function() {
    processData(_input);
});

3 个答案:

答案 0 :(得分:2)

循环数组一次以找到总和。声明两个变量:sumLeft和sumRight。 sumLeft的初始值应为0,sumRight应为totalSum-arr [0]。

再次遍历数组并通过(n-1)元素递增sumLeft并将sumRight递减第n个元素。继续比较这两个变量,检查它们是否相等。你将时间复杂度降低到O(n)

以下代码通过了https://www.hackerrank.com/challenges/sherlock-and-array的测试。棘手的部分是设置数组长度为1时的默认响应。我将承认@trincot的答案对于只包含正整数的数组更有效(n而不是2n)。

 function check(input) {
    var result = "NO";
    var sum=0;

     if(input.length == 1){
        console.log("YES");
        return;
     }

    input.map(function(data){
        sum=sum+(+data);
    })
    sumLeft=0;
    sumRight=sum-(+input[0]);

    for(var i=1;i<input.length-1;i++){
        sumLeft=sumLeft+(+input[i-1]);
        sumRight=sumRight-(+input[i])
        if(sumLeft==sumRight)
        {
            console.log("YES");
            return;
        }else if (sumLeft>sumRight) {  ///worked both with and without this optimization
            console.log("NO"); 
            return;
        }
    }
    console.log("NO");
}



function processData(input) {

    //var lines = input.split("\r\n");
    var lines = input.split(/\r|\n/)
    for (var m = 2; m < lines.length; m = m + 2) {
        check(lines[m].split(" "));
    }
}
process.stdin.resume();
process.stdin.setEncoding("ascii");
_input = "";
process.stdin.on("data", function(input) {
    _input += input;
});
process.stdin.on("end", function() {
    processData(_input);
});

答案 1 :(得分:1)

你可以使用两个指针(索引)从内向两端穿过数组。保持平衡,从0开始,如下所示:

当余额为负时,将左指针向右移动一步,同时使用您留下的值增加余额。当余额为正时,将右指针向左移动一步,同时使用您留下的值减少余额。

当两个指针相遇时,检查天平。如果它为零,那么你就获得了成功。

以下是ES6代码中的算法,以及可根据所需输入格式调整输入的文本区域:

function hasMiddle(a) {
    var balance = 0, i = 0, j = a.length-1;
    while (i < j) balance += balance > 0 ? -a[j--] : a[i++];
    return !balance;
}

// I/O: event handling, parsing input, formatting output

var input = document.querySelector('textarea');
var output = document.querySelector('pre');

input.oninput = function() {
    var lines = this.value.trim().split(/[\r\n]+/).filter(s => s.trim().length);
    // Strip the case count and array element counts:
    lines = lines.slice(1).filter( (s, i) => i % 2 ); 
    // Call function for each test case, returning array of booleans:
    var results = lines.map( line => hasMiddle(line.match(/\d+/g).map(Number)) );
    // Output results
    output.textContent = results.map( pos => pos ? 'YES' : 'NO' ).join('\n');
}
// Evaluate input immediately
input.oninput();
Input:<br>
<textarea style="width:100%; height:120px">2 
3
 1 2 3

4
 1 2 3 3
</textarea>
<pre></pre>

此算法要求输入数组由非负数组成。

如果你需要支持数组中的负数,那么算法需要首先通过数组来计算总和,然后再次遍历数组以找到余额达到0的点:

function hasMiddle(a) {
    var balance = a.reduce( (sum, v) => sum + v );
    return !a.every ( (v, i) => balance -= v + (i ? a[i-1] : 0) );
}
// I/O for snippet

var input = document.querySelector('textarea');
var output = document.querySelector('pre');

input.oninput = function() {
    var lines = this.value.trim().split(/[\r\n]+/).filter(s => s.trim().length);
    // Strip the case count and array element counts:
    lines = lines.slice(1).filter( (s, i) => i % 2 ); 
    // Call function for each test case, returning array of booleans:
    var results = lines.map( line => hasMiddle(line.match(/[\d-]+/g).map(Number)));
    // Output results
    output.textContent = results.map( pos => pos ? 'YES' : 'NO' ).join('\n');
}
// Evaluate input immediately
input.oninput();
Input:<br>
<textarea style="width:100%; height:120px">2 
3
 1 2 3

4
 1 2 3 3
</textarea>
<pre></pre>

答案 2 :(得分:0)

鉴于我们有一个合适的数组,可以按如下方式执行

var arr = [...Array(35)].map(_ => ~~(Math.random()*10)+1),
    sum = arr.reduce((p,c) => p+c),
   half = Math.floor(sum/2),
     ix;
console.log(JSON.stringify(arr));
  midix = arr.reduce((p,c,i,a) => { (p+=c) < half ? p : !ix && (ix = i);
                                    return i < a.length - 1  ? p : ix;
                                  },0);
console.log("best possible item in the middle @ index", midix,": with value:",arr[midix]);
console.log("sums around midix:",
            arr.slice(0,midix)
               .reduce((p,c) => p+c),
            ":",
            arr.slice(midix+1)
               .reduce((p,c) => p+c));

当然,对于上面随机填充的数组,我们不能总是得到一个完美的中间索引。