我该如何解决这个问题,以及解决该问题的合适算法是什么

时间:2020-08-11 10:47:06

标签: java algorithm

有一个包含非负整数的数组。我需要找到一个子数组(如果有的话),其中包含的数字之和等于给定数字(目标)的数字。我编写的代码行得通,但我尝试以更有效的方式编写代码(O(n))。

public static void solvedNotSoEnhanced(int[] arr, int target) {
    for (int i = 0; i <= arr.length-1;i++) {
        int cur_sum = 0;
        for (int j = i ; j <= arr.length-1; j++) {
            cur_sum += arr[j];
            if (cur_sum > target) {
                break;
            } else if (cur_sum == target) {
                System.out.println("start: " + i + " end: " + j);
            }
        }
    }
}

3 个答案:

答案 0 :(得分:3)

诀窍在于限制:

有一个包含非负整数的数组。

这意味着当您从头到尾浏览输入时,您假定子数组的“开始”在索引0处,然后开始按顺序添加每个数字。仅有3个选项,因为有该限制:

  1. 添加新数字将导致总和小于所需数字。在这种情况下,请继续。
  2. 添加新号码会导致与所需号码完全匹配。您已经找到了子序列,算法就完成了。
  3. 添加新数字会得出总和。在这种情况下,唯一的答案可能是向上移动 start :元素0不是解决方案的一部分。

因此:

static void solvedNotSoEnhanced(int[] arr, int target) {
    if (target < 1) {
        // Always mind your corner cases!
        System.out.println("(0, 0)");
        return;
    }

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

        while (sum > target) {
            // Target exceeded; move up our startpoint.
            sum -= arr[start];
            start++;
        }

        // If we get here, we found our subsequence!
        if (sum == target) {
            System.out.println("[" + start + ", " + i + "]");
            return;
        }
    }
    return "No subsequence";
}

答案 1 :(得分:2)

在这里,我使用了滑动窗口方法。我遍历它们时主要是存储数组元素的总和。然后,我只存储2个指针i和j,它们存储正在考虑的当前子数组的位置。

public static void solvedNotSoEnhanced(int[] arr, int target) 
{
  for(int i = 1;i>arr.length;i++)
  {
    arr[i] += arr[i-1];
  }
  
  int i=0,j=1;
  while(i<arr.length &&j<arr.Length)
  {
    int sum = arr[j] - arr[i];
    if(sum == target) System.out.println("start: " + (i + 1) + " end: " + j);
    else if(sum > target) i++;
    else j++;
  }
}

答案 2 :(得分:1)

可以在O(nlogn + m)中完成,其中n是数组大小,m是与限制条件匹配的子数组的数量。

首先,创建一个辅助数组sum,该数组是直到当前为止所有元素的总和:

sum[i] = arr[0] + arr[1] + ... + arr[i]
Or (equivalent definition)
sum[0] = arr[0]
sum[i] = sum[i-1] + arr[i]

现在,请注意sum是经过排序(递增)的数组(因为所有元素都不都是负数)。

因此,在生成数组之后,您可以迭代sum,对于i中的每个sum,请使用二进制搜索查找k-sum[i],这将为您提供如果元素存在并且(i,j)是这样的子数组,则索引j

也可以使用哈希表存储总和,以进一步将平均情况下的复杂度降低到O(n)