有一个包含非负整数的数组。我需要找到一个子数组(如果有的话),其中包含的数字之和等于给定数字(目标)的数字。我编写的代码行得通,但我尝试以更有效的方式编写代码(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);
}
}
}
}
答案 0 :(得分:3)
诀窍在于限制:
有一个包含非负整数的数组。
这意味着当您从头到尾浏览输入时,您假定子数组的“开始”在索引0处,然后开始按顺序添加每个数字。仅有3个选项,因为有该限制:
因此:
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)
。