【问题标题】:javascript hackerranks sherlock and array performance issuejavascript hackerrank sherlock和数组性能问题
【发布时间】:2016-10-06 16:28:20
【问题描述】:

Watson 给 Sherlock 一个长度为 N 的数组 A。然后他让他 确定数组中是否存在一个元素,使得 它左边的元素等于它的元素之和 正确的。如果左/右没有元素,则总和为 被认为是零。形式上,找到一个 i,这样,

输入格式

第一行包含 T,测试用例的数量。对于每个测试 情况下,第一行包含 N,数组中的元素个数 A. 每个测试用例的第二行包含 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);
});

【问题讨论】:

    标签: javascript arrays algorithm performance


    【解决方案1】:

    遍历数组一次以求和。声明两个变量:sumLeft 和 sumRight。 sumLeft 的初始值应为 0,sumRight 应为 totalSum-arr[0]。

    再次遍历数组,将 sumLeft 增加 (n-1) 个元素,将 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);
    });
    

    【讨论】:

    • 您需要通过 same 元素增加一个并减少另一个
    • 其实没有,因为它是左边的元素
    • 您好,我已按照建议进行了修改,但没有成功。
    • 如果数组只能包含正整数,您可以在 sumLeft 大于 sumRight 时停止进一步优化
    • 还是超时问题吗?
    【解决方案2】:

    您可以使用两个指针(索引)从两端向内遍历数组。保持平衡,从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>

    【讨论】:

    • 谢谢 trincot,
    【解决方案3】:

    假设我们有一个合适的数组,我们可以这样做

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-13
      • 2019-10-08
      • 2022-09-25
      • 2012-06-22
      相关资源
      最近更新 更多