如何解决这个问题,以及是否有适合解决它的算法。

huangapple go评论75阅读模式
英文:

How can I solve this problem, and what kind of algorithm is the appropriate on if any to solve it

问题

这段代码是用于查找一个包含非负整数的数组中,是否存在一个子数组,其元素之和等于给定的目标值(target)。以下是这段代码的翻译:

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("起始位置: " + i + " 终止位置: " + j);
            }
        }
    }
}

希望这个翻译对您有所帮助。如果您有任何其他需要,请随时提出。

英文:

There is an array which contains non negative integers. I need to find a subarray (if there's one) that contains numbers that have a sum which equals to a given number (target). I wrote this code that works but I try to write it in a more efficient way (O(n)).

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

答案1

得分: 3

这个技巧在于限制条件:

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

这意味着当你按照输入的顺序从前往后遍历时,假设子数组的“开始”位于索引0,然后依次开始添加每个数字。由于这个限制条件,只有3种可能性:

  1. 添加新数字导致总和小于目标数字。在这种情况下,继续前进。
  2. 添加新数字导致与目标数字完全匹配。你已经找到了子序列,算法完成。
  3. 添加新数字导致总和更大。在这种情况下,唯一的答案可能是移动“开始”位置:元素0不是解的一部分。

因此:

static void solvedNotSoEnhanced(int[] arr, int target) {
    if (target < 1) {
        // 始终注意边界情况!
        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) {
            // 超过目标值;将起始点向上移动。
            sum -= arr[start];
            start++;
        }

        // 如果我们到达这里,我们找到了子序列!
        if (sum == target) {
            System.out.println("[" + start + ", " + i + "]");
            return;
        }
    }
    System.out.println("没有子序列");
}
英文:

The trick lies in the restriction:

> There is an array which contains non negative integers.

This means that when you're going through your input front-to-back, you presume that the 'start' of the subarray is at index 0, and then you start adding each number in sequence. There are only 3 options, because of that restriction:

  1. Adding the new number results in a sum that is less than the desired number. In which case, keep going.
  2. Adding the new number results in an exact match to the desired number. You've found the subsequence and the algorithm is done.
  3. Adding the new number results in a sum that is more. In which case, the only answer can lie in moving the start up: Element 0 is not part of the solution.

Thus:

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

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

        while (sum &gt; 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(&quot;[&quot; + start + &quot;, &quot; + i + &quot;]&quot;);
            return;
        }
    }
    return &quot;No subsequence&quot;;
}

答案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++;
  }
}
英文:

Here I have used sliding window approach. Mainly I am storing the sum of elements of array as I traverse them. Then I just store 2 pointers i and j which store the position of current sub array under consideration.

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

答案3

得分: 1

可以在O(nlogn + m)的时间复杂度内完成,其中n是数组大小,m是符合限制条件的子数组数量。

首先,创建一个辅助数组sum,它是当前位置之前所有元素的累加和:

sum[i] = arr[0] + arr[1] + ... + arr[i]
或者(等价定义)
sum[0] = arr[0]
sum[i] = sum[i-1] + arr[i]

现在,注意到sum是一个已排序的(递增)数组(因为所有元素都是非负的)。

因此,在生成数组后,您可以遍历sum,对于sum中的每个i,使用二分查找来查找k-sum[i],这将给您索引j,如果元素存在,那么(i, j)就是这样一个子数组。

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

英文:

It can be done in O(nlogn + m), where n is the array size, and m is the number of subarrays matching the restriction.

First, create an auxillary array sum, which is the summation of all elements up to the current:

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

Now, note that sum is sorted (increasing) array (since all elements are not negative).

So, after the array is generated, you can iterate sum, and for each i in sum, look for k-sum[i] using binary search, which will give you index j if the element exists, and (i,j) is such a subarray.

Using a hash table to store the sums instead can also be done to further reduce complexity to O(n) on average case.

huangapple
  • 本文由 发表于 2020年8月11日 18:47:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/63356582.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定