Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 降低查找数组元素绝对和的复杂性_Java_Performance_Time Complexity - Fatal编程技术网

Java 降低查找数组元素绝对和的复杂性

Java 降低查找数组元素绝对和的复杂性,java,performance,time-complexity,Java,Performance,Time Complexity,我在Hackerrank上遇到了这个问题。 给定一个整数数组,您必须回答许多查询。每个查询由单个整数x组成,执行方式如下: 将x添加到数组的每个元素中,永久地修改它以备将来查询 找到数组中每个元素的绝对值,并在新行上打印绝对值之和 我只需要完成以下方法 static int[] solution(int[] arr, int[] queries) 这里,arr是包含n元素的数组 和查询包含我需要与数组arr的每个值相加的所有x,然后得到arr元素的绝对和。因此,结果数组的大小将与数组查询

我在Hackerrank上遇到了这个问题。

给定一个整数数组,您必须回答许多查询。每个查询由单个整数x组成,执行方式如下:

  • 将x添加到数组的每个元素中,永久地修改它以备将来查询
  • 找到数组中每个元素的绝对值,并在新行上打印绝对值之和
我只需要完成以下方法

static int[] solution(int[] arr, int[] queries)
这里,
arr
是包含
n
元素的数组 和
查询
包含我需要与数组
arr
的每个值相加的所有
x
,然后得到
arr
元素的绝对和。因此,结果数组的大小将与数组
查询的大小相同,即大小为
m
。该方法将返回一个
m
元素数组

下面是我的实现

       static int[] solution(int[] arr, int[] queries)
       {

          int[] result = new int[queries.length];

          for (int i = 0; i < queries.length; i++)
          {
             int total = 0;

             for (int j = 0; j < arr.length; j++)
             {
                arr[j] += queries[i];

                if (arr[j] > 0)
                   total += arr[j];
                else
                   total -= arr[j];
             }
             result[i] = total;
          }

          return result;
       }
静态int[]解决方案(int[]arr,int[]查询)
{
int[]结果=新的int[querys.length];
for(int i=0;i0)
总+=arr[j];
其他的
总计-=arr[j];
}
结果[i]=总数;
}
返回结果;
}
它工作得很好,它的复杂度是
O(mn)
,但我需要用
O(nlog_m)
O(mlog_n)
的复杂度来完成它。


静态int[]解决方案(int[]arr,int[]查询)
{
int querySum=0;
for(int i;i

复杂度为O(n),额外内存消耗为O(1)

答案

基本上,如果您知道有多少个数字是正的,有多少个是负的,您可以将这两个计数乘以累计查询总数(负数为*-1)

计算出有多少-/+的总计数以及每个步骤中所有这些值的总和。例如,将+1加到全部,直到所有负数都为正数;将-1加到全部,直到所有正数都为负数。存储每个步骤的结果(所有-/+计数和所有-/+值的总和)

现在,您可以引用每个步骤的总和和总计数-/+来计算每个查询的结果

您还需要将playingWithNumbers方法和结果数组的返回类型从int更改为long

static long[] playingWithNumbers(int[] arr, int[] queries) {

    long[] results = new long[queries.length];

    List<Integer> negatives = new ArrayList<>(arr.length);
    List<Integer> positives = new ArrayList<>(arr.length);

    long negativeSum = 0;
    long positiveSum = 0;
    for (int i : arr) {
        if (i < 0) {
            negatives.add(i);
            negativeSum += i;
        } else {
            positives.add(i);
            positiveSum += i;
        }
    }
    int negativeCount = negatives.size();
    int positiveCount = positives.size();
    Collections.sort(negatives);
    Collections.sort(positives);

    Map<Integer, Integer> countMap = new HashMap<>(arr.length);
    Map<Integer, Long> sumMap = new HashMap<>(arr.length);
    long totalSum = positiveSum + (negativeSum * -1);
    countMap.put(0, negativeCount);
    sumMap.put(0, totalSum);

    if (positiveCount != 0) {
        long tmpTotalSum = totalSum;
        int tmpNegativeCount = negativeCount;
        int increment = negativeCount - positiveCount;
        int index = 0;

        for (int i = 1; i <= positives.get(positiveCount - 1) + 1; i++) {
            while (index != positives.size() && positives.get(index) - i == -1) {
                tmpNegativeCount++;
                increment += 2;
                index++;
            }
            tmpTotalSum += increment;
            countMap.put(i * -1, tmpNegativeCount);
            sumMap.put(i * -1, tmpTotalSum);
        }
    }

    if (negativeCount != 0) {
        long tmpTotalSum = totalSum;
        int tmpNegativeCount = negativeCount;
        int increment = positiveCount - negativeCount;
        int index = negativeCount - 1;

        for (int i = 1; i <= (negatives.get(0) - 1) * -1; i++) {
            int incrementNxt = 0;
            while (index != -1 && negatives.get(index) + i == 0) {
                tmpNegativeCount--;
                incrementNxt += 2;
                index--;
            }
            tmpTotalSum += increment;
            increment += incrementNxt;
            countMap.put(i, tmpNegativeCount);
            sumMap.put(i, tmpTotalSum);
        }
    }

    int maxNegative = positiveCount != 0 ? (positives.get(positiveCount - 1) + 1) * -1 : 0;
    int maxPositive = negativeCount != 0 ? ((negatives.get(0) - 1)) * -1 : 0;
    int totalCount = positiveCount + negativeCount;
    long accumulatedTotal = 0;

    for (int i = 0; i < queries.length; i++) {
        accumulatedTotal += queries[i];

        if (accumulatedTotal >= maxNegative && accumulatedTotal <= maxPositive) {
            results[i] = sumMap.get((int)accumulatedTotal);
        } else if (accumulatedTotal < maxNegative) {
            long extra = maxNegative - accumulatedTotal;
            results[i] = sumMap.get(maxNegative) + countMap.get(maxNegative) * extra;
        } else {
            long extra = accumulatedTotal - maxPositive;
            results[i] = sumMap.get(maxPositive) + (totalCount - countMap.get(maxPositive)) * extra;
        }
    }

    return results;
}
static long[]playingWithNumbers(int[]arr,int[]querys){
long[]results=new long[querys.length];
列表负片=新数组列表(arr.length);
列表正片=新数组列表(arr.length);
长负esum=0;
长阳性率um=0;
用于(int i:arr){
if(i<0){
否定。加入(i);
负esum+=i;
}否则{
增加(i);
阳性血清um+=i;
}
}
int negativeCount=negatives.size();
int positiveCount=posities.size();
集合。排序(负片);
集合。排序(正数);
Map countMap=新的HashMap(arr.length);
Map sumMap=新HashMap(arr.length);
长总和=正总和+(负总和*-1);
countMap.put(0,负计数);
总和put(0,总和);
如果(正计数!=0){
长tmpTotalSum=总和;
int tmpNegativeCount=负计数;
int增量=负计数-正计数;
int指数=0;

对于(inti=1;i而言,受以下链接中h4z3给出的解释的启发,

我已经用Java实现了这个想法

复杂性为O(n logn)。

   static int bisect_left(int[] num, int x)
   {
      int low = 0;
      int high = num.length - 1;

      while (low < high)
      {
         int mid = (low + high) / 2;

         if (num[mid] >= x)
            high = mid - 1;
         else
            low = mid + 1;
      }

      return (num[low] < x) ? low + 1 : low;
   }

   static int[] solution(int[] arr, int[] queries)
   {
      Arrays.sort(arr); // O(n log n)

      int N = arr.length;

      int[] results = new int[queries.length];
      int[] sc = new int[N + 1];
      sc[0] = 0;
      sc[1] = arr[0];

      for (int i = 1; i < N; i++)
         sc[i + 1] = sc[i] + arr[i];

      int q = 0;
      for (int i = 0; i < queries.length; i++)  //  O(m)
      {
         q += queries[i];

         int n = bisect_left(arr, -q);  //  O(log n)

         results[i] = sc[N] + q * N - 2 * (sc[n] + q * n);
      }

      return results;
   }
static int bisect_left(int[]num,int x)
{
int低=0;
int高=num.length-1;
while(低<高)
{
int mid=(低+高)/2;
如果(num[mid]>=x)
高=中-1;
其他的
低=中+1;
}
返回(数值[低]问题:寻求帮助优化当前正在运行的代码通常更适合。你可能会考虑迁移你的问题到那里。首先我问了CoDeEvIEW.StActhExchange。com,有人说,因为我正在寻找新的实现,我应该在这里问。所以我删除它,并在这里问。你可以保持<代码>rr
在一个外部变量中的和,以及
查询中整数的合计和
@azurefrog不太可能,CR不仅仅是一个优化。OP的代码不多,当它需要完全重写时,没有必要使它更好。你错过了“绝对值”.Hm,是的,你是对的,但它不会改变复杂性和内存消耗@Alexey,对于arr[]={0,-2,-3,2}和querys[]={-2,4,-1}来说,它仍然是错误的。输出应该是{11,7,7},你的答案将生成大小为4的数组,而不管查询大小如何。你能添加几个吗