儿童糖果Hackerrank面临的挑战:优化解决方案

时间:2019-03-27 07:05:31

标签: javascript algorithm optimization

我正在尝试解决JavaScript中的hackerrank难题,尽管对于大多数测试实例来说,我的解决方案表现都不错,但我仍然为其中一些超时(Hackerrank将其设置为10秒JavaScript挑战)。问题描述如下:

  

有N个孩子排成一列。最初,第i个孩子有一个[i]   糖果。有些孩子的糖果比其他孩子更多。你有   确保每个学生拥有相同数量的糖果。合而为一   你可以告诉一个孩子给一个糖果   左边的邻居,或者右边的邻居。你做了多少次手术   需要确保每个学生拥有相同数量的糖果吗?打印   尽可能减少操作次数。输入是多行   字符串,第一行包含一个整数N,第二行   行包含N个以空格分隔的整数。

我通过计算应该给每个孩子多少糖果的数量解决了这个问题,然后迭代包含糖果数量的数组,或者从最右边的位置抓取糖果(以防孩子没有足够的糖果数量) ),或将糖果传递到正确的位置(以防孩子需要的糖果过多)

这是我用于挑战的代码:

function processData(input) {
    let tmp = input.split(/\n| /),
        n = tmp[0]    

    tmp.shift()  // remove first element from tmp (the N variable)

    let s=0, a = tmp.map(function(ai) {novo=parseInt(ai, 10);s+=novo;return(novo)}),
        obj = s/n, ops = 0

    for(var i=0; i<n; i++) {

        if(a[i] > obj) {
            let moved = a[i]-obj
            a[i]-=moved
            a[i+1]+=moved
            ops+=moved
        }
        else {
            for(var j=i+1; a[i] != obj; j++) {


                if(a[j]===0) {
                    ops++
                }
                else {
                    let moved = Math.min(a[j], obj-a[i])
                    a[i]+=moved
                    a[j]-=moved
                    ops+=moved
                }
            }        
        }

        //console.log(a)
    }

    console.log(ops)
}

有什么问题的想法吗?

您如何优化我的代码?

链接到挑战:https://www.hackerrank.com/contests/coc1/challenges/candies-1

编辑 经过一些优化后,我的解决方案现在使3个测试用例失败(由于超时而失败)。这不是性能问题

2 个答案:

答案 0 :(得分:2)

问题是,您需要为每个孩子进行几次平均移动计数。

  

例如,以这排孩子为例,

1  4  2  7  1
     

从第一个孩子开始,看看它有多少个物品,应该有多少个物品。取(绝对)差来计算移动次数,并给第一个孩子一个平均值。下一个孩子获得第一个孩子的差额。在这种情况下,给出两个项目之后,它便具有两个项目。

     

然后查看该行中的下一个孩子。重复上面的操作,您可以在一个循环中获得所有子代的移动次数。

   children     moves 
--------------- -----
 1  4  2  7  1     2
<3  2> 2  7  1     1
 3 <3  1> 7  1     2
 3  3 <3  5> 1     2
 3  3  3 <3  3>
--------------- -----
                   7

<x  y> denotes a group of changing values
     

示例2

   children     moves 
--------------- -----
 7  4  2  1  1     4
<3  8> 2  1  1     5
 3 <3  7> 1  1     4
 3  3 <3  5> 1     2
 3  3  3 <3  3>
--------------- -----
                  15

function processData(input) {
    var [length, ...values] = input.split(/\\n|\s/),
        i,
        moves = 0,
        value = 0,
        sum = 0,
        avg;
        
    for (i = 0; i < +length; i++) sum += +values[i];
    avg = sum / length;

    for (i = 0; i < length - 1; i++) {
        value += +values[i];
        moves += Math.abs(value - avg);
        value -= avg;
    }
    
    return moves;
}

console.log(processData('5\n1 4 2 7 1')); //  7
console.log(processData('5\n7 4 2 1 1')); // 15
console.log(processData('3\n1 2 3'));     //  2

答案 1 :(得分:2)

您的解决方案似乎是O(n ^ 2),但应该可以在O(n)中解决:

function processCandyArray(candies) {
    let sum = 0, steps = 0, carry = 0
    for (let i = 0; i < candies.length; i++)
        sum += candies[i]
    let avg = sum / candies.length
    for (let i = 0; i < candies.length - 1; i++) {
        carry = candies[i] + carry - avg
        steps += carry > 0 ? carry : -carry
    }
    return steps
}

您可以在计算平均值后浏览数组,并在每个位置计算结转多少个糖果(左为正进位,右为负进位),然后对绝对进位求和。