Javascript 运行时错误和时间复杂性问题:最小化值|(A[0]+…+A[P-1])-(A[P]+…+A[N-1])|

Javascript 运行时错误和时间复杂性问题:最小化值|(A[0]+…+A[P-1])-(A[P]+…+A[N-1])|,javascript,big-o,time-complexity,array-algorithms,Javascript,Big O,Time Complexity,Array Algorithms,我最近解决了一个编码问题。我想出了以下问题的解决办法 给出了一个由N个整数组成的非空零索引数组。数组A表示磁带上的数字。 任何整数P,使得0

我最近解决了一个编码问题。我想出了以下问题的解决办法

给出了一个由N个整数组成的非空零索引数组。数组A表示磁带上的数字。 任何整数P,使得0 以下是我从测试解决方案中获得的反馈:

正确性: 小范围序列,长度=~1000 1.900 s运行时错误 测试程序意外终止 性能: 检测到的时间复杂度:开*N

所以我得到了一个运行时错误,范围约为1000。最重要的是,我没有进步。我在使用嵌套for循环时使用*n

1如何修复运行时错误? 2.对于同一个问题,如何构建算法?有什么建议吗

这是我的解决方案:

    function solution(A){
        var len = A.length;
        var diff = [];  // Array to store the differences
        var sumLeft = 0;    // Sum of array elements from index 0 to index p - 1
        var sumRight = 0;   // Sum of array elements from index p to index n - 1
        for(var p = 1; p < len; p++){
            sumLeft = 0;
            sumRight = 0;
            // Calculate sumLeft:
            for(var i = 0; i < p; i++){
                sumLeft += A[i];
            }
            // Calculate sumRight:
            for(var j = p; j < len; j++){
                sumRight += A[j];
            }
            // Calculate differences, compute absolute values, and push into diff array:
            diff.push(Math.abs(sumLeft - sumRight));
        }
        // Return the minimum of diff array by sorting it and returning the first element:
        return bubbleSort(diff)[0];
    }

    function bubbleSort(array){
        var len = array.length;
        for(var i = 0; i < len; i++){
            for(var j = i + 1; j < len; j++){
                if(array[i] > array[j]){
                    var temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }
            }
        }
        return array;
    }

在测试新的p值时,不需要计算向量块的和。如果计算了p=p-1的两部分的leftSum和rightSum,当必须计算p=p时,只需要:

从rightSum中删除数组[p];和 将数组[p]添加到leftSum。 这两个都是O1。如果你做了n-1次,你的复杂性仍然很低


希望这能有所帮助。

让我试着向您解释一下如何考虑提高算法的空间和时间复杂性。您清楚地意识到,您正在使用嵌套for循环,这大大增加了迭代次数,并且可能会导致足够大的输入的运行时错误

第一步应该是减少操作的冗余。现在,重复计算p的不同值的左和右总和。你根本不需要这个。我将为您提供一个算法流程的示例:

 Array indices -> A [0, 1, 2, 3, ....,p ,p+1, ....n-1] for a size n array

 At any point A[p] would act as a pivot as it breaks the array into two.
 For p = 1, You just take the first element i.e A[0] and the right part of the sum is
 A[1] + A[2] + .... A[n-1]

 Let S1 = A[0] and S2 = A[1] + A[2] + .... A[n-1] for p = 1
 The pivot or the break point here is A[p] i.e A[1]

 Calculate the absolute difference |S1- S2| and store it in a variable min-diff

 For p = 2, 

 S1 will simply be S1 + A[1] i.e the previous value of S1 including the last pivot 

 S2 = S2 - A[1], as we have moved on to the next element. 
 The sum of the remaining elements would not account the element we just crossed.

Formally,

S1 = S1 + A[p-1] and S2 = S2 - A[p-1]

Calculate the new difference i.e |S1 - S2| and just check 
if it is smaller than the value of our variable min-diff. 
If it is, update the value of min-diff with the present difference, 
otherwise move on to the next element.

At any value of p, S1 represents sum of left half, 
S2 represents sum of right half and 
min-diff represents the minium absolute difference till now.
该算法的复杂度 时间复杂性

我们计算元素之和的唯一时间是第一次 当我们计算A[1]+…A[n-1]时。在那之后,我们只需穿过 数组的元素一个接一个

所以我们在max处遍历数组的元素两次。所以时间 复杂性显然在上升

空间复杂性

我们始终使用三个额外变量,即S1、S2和min diff 此算法用于累加和和存储最小绝对值 随着p和n元素值的不同 数组

所以这个算法的空间复杂度又开始了

另一方面,尽管您根本不需要对这个问题进行排序,因为您只需要输出最小的差异,但无论何时进行排序,请不要使用冒泡排序,因为它显然是效率最低的排序方法。最好使用运行时间为ONlogN的合并排序或快速排序

我希望我能解释我自己。尝试将其编码为一个简单的函数,不会花费太长时间。它可能也会修复运行时错误。

使用java:ON编写代码

import java.math.*;

class Solution {

  public int solution(int[] A) {

    long sumright = 0;
    long sumleft = 0;
    long ans;

    for (int i =1;i<A.length;i++)
    {
      sumright += A[i];
    }

    sumleft = A[0];
    ans =Math.abs(sumright+sumleft);

    for (int P=1; P<A.length; P++)
    {
      if (Math.abs(sumleft - sumright)<ans)
      {
        ans = Math.abs(sumleft - sumright);
      }
      sumleft += A[P];
      sumright -=A[P];
    }
  return (int) ans;
}

}

在不进行调试的情况下,此解决方案在可编程性方面获得100%的任务分数,在正确性和性能方面都达到100%:

function solution(A) {
    var sum_right = 0;

    for (int of A.slice(1)) {
        sum_right += int;
    }

    var sum_left = A[0];
    var diff_of_sums = sum_left - sum_right;
    var lowest_diff = Math.abs(diff_of_sums);
    var diff_new;
    // we assume the length is at least 2
    if (A.length == 2) {
        return lowest_diff;
    }
    for (var int of A.slice(1)) {
        diff_new = Math.abs(sum_left - sum_right);
        if (diff_new < lowest_diff) {
            lowest_diff = diff_new;
        }
        sum_left += int;
        sum_right -= int;
    }
    return lowest_diff;
}
通过调试:

// you can write to stdout for debugging purposes, e.g.
// console.log('this is a debug message');

function solution(A) {
    var sum_right = 0;

    for (int of A.slice(1)) {
        sum_right += int;
    }

    var sum_left = A[0];
    var diff_of_sums = sum_left - sum_right;
    // var total = Math.abs(sum_left + sum_right);
    var lowest_diff = Math.abs(diff_of_sums);
    var diff_new;
    // we assume the length is at least 2
    if (A.length == 2) {
        return lowest_diff;
    }
    // console.log("lowest_diff initially:", lowest_diff)
    // var diff_of_sums_new = diff_of_sums;
    // console.log("diff_of_sums initially:", diff_of_sums)
    // console.log("A.slice(1):", A.slice(1))
    for (var int of A.slice(1)) {
        // console.log("lowest_diff", lowest_diff)
        diff_new = Math.abs(sum_left - sum_right);
        if (diff_new < lowest_diff) {
            lowest_diff = diff_new;
        }
        sum_left += int;
        sum_right -= int;
    }
    //           if (Math.abs(sumleft - sumright)<ans)
    //   {
    //     ans = Math.abs(sumleft - sumright);
    //   }
    //   sumleft += A[P];
    //   sumright -=A[P];
    //     // console.log("int === -1:", int === -1);
    //     // diff_of_sums = diff_of_sums_new;
    //     console.log("lowest_diff =", lowest_diff);
    //     // console.log("A[index + 1] =", A[parseInt(index) + 1]);
    //     // console.log("parseInt(index) === 1", parseInt(index) === 1)
    //     diff_of_sums = Math.abs(lowest_diff - 2 * Math.abs(int));
    //     // console.log("diff_of_sums =", diff_of_sums);
    //     // console.log("diff_of_sums = Math.abs(diff_of_sums - 2 * A[index + 1]) = ", diff_of_sums_new);
    //     if (diff_of_sums < lowest_diff) {
    //         lowest_diff = diff_of_sums;
    //         // console.log("lowest_diff = diff_of_sums =", diff_of_sums_new)
    //     } else {
    //         return lowest_diff;
    //     }
    // }
    // console.log("lowest_diff before returning", lowest_diff);
    return lowest_diff;
}
// Note that it's better to use test cases in Codility for this, but I've left here to show some.
// console.log("solution([-1000, 1000])", solution([-1000, 1000]));
// console.log("solution([2, 7, 20, 30, 1])", solution([2, 7, 20, 30, 1])); // sum 60, smallest diff = |29 - 31| = 2
// console.log("solution([-2, -7, -20, -30, -1])", solution([-2, -7, -20, -30, -1])); // sum -60, smallest diff = 2
// console.log("solution([-1, -1]):", solution([-1, -1]));
// console.log("solution([-2, -1]):", solution([-2, -1]));
// console.log("solution([-2, -1, -3]):", solution([-2, -1, -3]));
// console.log("solution([]):", solution([]))
最初我尝试从一半开始,但这使得实现更加复杂。这就是我在放弃这种方法之前想到的,我不会为破解解决方案而烦恼:

function solution(A) {
    // const sum = A.reduce((partial_sum, a) => partial_sum + a); 
    // console.log(sum);
    var size = A.length;
    if (size % 2 == 0) {
        mid = size/2;
    } else {
        mid = Math.floor(size/2);
    }
    console.log("mid initially", mid);
    var sum1 = A.slice(0, mid).reduce((partial_sum, a) => partial_sum + a);
    // console.log("sum1:",sum1);
    var sum2 = A.slice(mid).reduce((partial_sum, a) => partial_sum + a);
    // console.log("sum2:", sum2);
    var sum_diff = sum1 - sum2;
    // console.log("sum_diff:", sum_diff);
    if (sum_diff === 0) {
        return sum_diff;
    }
    // sum_diff = function() {Math.abs(sum2 - sum1)};
    // sum_diff = sum_diff();
    var lowest_diff = Math.abs(sum_diff);
    var diff_negative = (sum_diff < 0);
    console.log("diff_negative initially:", diff_negative)
    var crossed_over = false;
    var sum_diff_new;
    while (diff_negative) {
        mid++;
        if (mid === size) {
            return lowest_diff;
        }
        // var sum1_new = sum1 + A[mid];
        // var sum2_new = sum2 - A[mid];
        // sum_diff_new = sum1_new - sum2_new = sum1 - sum2 + 2*A[mid] = sum_diff - 2*A[mid];
        sum_diff_new = sum_diff - 2*A[mid];
        diff_negative = (sum_diff_new < 0);
        if (diff_negative = false) {
            crossed_over = true;
            if (lowest_diff <= sum_diff_new) {
                return lowest_diff;
            } else {
                return sum_diff_new;
            }
        }
    }

    while(!diff_negative) {
        mid--;
        if (mid === -1) {
            return lowest_diff;
        }
        // var sum1_new = sum1 - A[mid];
        // var sum2_new = sum2 + A[mid];
        // sum_diff_new = sum1_new - sum2_new = sum1 - sum2 - 2*A[mid] = sum_diff - 2*A[mid];
        console.log("sum_diff:", sum_diff);
        sum_diff_new = sum_diff + 2*A[mid];
        console.log("sum_diff_new:", sum_diff_new);
        diff_negative = (sum_diff_new < 0);
        if (diff_negative = true) {
            crossed_over = true;
            var sum_diff_new_pos = Math.abs(sum_diff_new);
            if (lowest_diff <= sum_diff_new_pos) {
                return lowest_diff;
            } else {
                return sum_diff_new_pos;
            }
        }
    }
}

// Issues: doesn't work e.g. with  [-2, -1, -3] and [-2, -7, -20, -30, -1]

鉴于abs函数的性质,您只需要迭代,直到右部分和左部分之间的差值开始增大。如果发生这种情况,您已经达到了最小值,并且在整个数组中进行操作是次优的。@Achrome,在问题中他提到数组的值可以是负值或正值
E我不知道我能否解释,在这种情况下,左右半和的绝对最小差值是否会有趋势。如果你们能进一步详细说明,我将不胜感激。非常感谢你们提供的见解。我觉得经过这次讨论后,我已经成为一个更加成熟和谨慎的程序员。这只得到了71%的编码正确率。如果只有两个元素[-10001000],并且小测试设计不起作用,那么它就不起作用。ans=Math.abssumright+sumleft;应重写为ans=Math.abssumright-sumleft;我会发布我的解决方案。