在 O(nlogn) 时间复杂度(使用分而治之)中找到和为 0 的子数组?
Find a subarray with sum 0 in O(nlogn) time complexity (Using Divide and Conquer)?
我在网上看过解决方案,但所有解决方案的时间复杂度都是 O(n) 或 O(n^2)。我想知道是否有可能在不使用辅助数据结构的 O(nlogn) 中找到和为 0 的子数组。但是,我们可以使用递归。
我们可以修改最大子数组和算法来找到这个问题的解吗?
输入数组将只有 1 和 -1,算法将找到和为 0 的子数组。
输入 = { 1, 1, -1, 1, -1, -1, 1, -1}
output = 1, 8(1 是起始索引,8 是最后一个索引)
在这种特殊情况下,整个输入数组的总和等于 0。因此,报告的起始和结束索引分别为 1 和 8(假设数组中的索引从 1 开始)。
编辑:我们可以使用这个问题的解决方案来解决另一个问题。该问题如下。
给定一个包含n个整数的数组arr,找到偶数元素和奇数元素数量相等的最长连续子数组。下面是一个示例(索引从 1 开始):
A = {8, 2, -3, 4, 9, 6}
答案:(2、5)。 (2 是起始索引,5 是最后一个索引)
唯一的限制是该算法不能使用任何辅助数据结构。在此约束下,解决方案必须是最有效的。此外,允许使用递归。
您可以使用递归算法,其中函数获取前一个数组值(如果有)的值,然后从输入数组中读取下一个值。如果它是相同的值,那么它递归地调用自己,当从那里返回时,它以相同的方式继续下一个值。如果它是相反的值,它 return 将发送给调用者 true
-- 以指示总和为零。如果遇到数组末尾,函数returns false
.
这实际上意味着递归的深度等于绝对累加和。因此,例如,如果数组是 [-1, -1, -1, 1],那么递归将进入深度 3,并且它将 return 从 level 3 到 level 2 with return值 true
。在级别 2 它将 return false
因为遇到了数组的末尾,所以它会退出递归。
每当 return 值为 true
时,您可以检查覆盖区间的大小是否大于目前遇到的区间大小。
下面是这个想法在 JavaScript 中的实现:
function zeroSum(arr) {
let i = 0; // index in the input array, managed outside of recursion
// Longest zero-sum interval so far. Zero based, and value at end index
// is not part of the interval:
let longest = [0, 0];
function recur(dir) { // dir is the previous value from the array (if any)
let start = i; // local variable
while (i < arr.length) {
let val = arr[i++];
if (val == -dir) return true; // zero sum
if (recur(val) && i - start > longest[1] - longest[0]) {
longest[0] = start;
longest[1] = i;
}
}
return false; // no zero sum
}
recur(0); // 0 is passed to indicate there is no previous value
return longest;
}
// demo
console.log(zeroSum([1, 1, -1, 1, -1, -1, 1, -1]));
我在网上看过解决方案,但所有解决方案的时间复杂度都是 O(n) 或 O(n^2)。我想知道是否有可能在不使用辅助数据结构的 O(nlogn) 中找到和为 0 的子数组。但是,我们可以使用递归。
我们可以修改最大子数组和算法来找到这个问题的解吗?
输入数组将只有 1 和 -1,算法将找到和为 0 的子数组。
输入 = { 1, 1, -1, 1, -1, -1, 1, -1}
output = 1, 8(1 是起始索引,8 是最后一个索引)
在这种特殊情况下,整个输入数组的总和等于 0。因此,报告的起始和结束索引分别为 1 和 8(假设数组中的索引从 1 开始)。
编辑:我们可以使用这个问题的解决方案来解决另一个问题。该问题如下。
给定一个包含n个整数的数组arr,找到偶数元素和奇数元素数量相等的最长连续子数组。下面是一个示例(索引从 1 开始):
A = {8, 2, -3, 4, 9, 6}
答案:(2、5)。 (2 是起始索引,5 是最后一个索引)
唯一的限制是该算法不能使用任何辅助数据结构。在此约束下,解决方案必须是最有效的。此外,允许使用递归。
您可以使用递归算法,其中函数获取前一个数组值(如果有)的值,然后从输入数组中读取下一个值。如果它是相同的值,那么它递归地调用自己,当从那里返回时,它以相同的方式继续下一个值。如果它是相反的值,它 return 将发送给调用者 true
-- 以指示总和为零。如果遇到数组末尾,函数returns false
.
这实际上意味着递归的深度等于绝对累加和。因此,例如,如果数组是 [-1, -1, -1, 1],那么递归将进入深度 3,并且它将 return 从 level 3 到 level 2 with return值 true
。在级别 2 它将 return false
因为遇到了数组的末尾,所以它会退出递归。
每当 return 值为 true
时,您可以检查覆盖区间的大小是否大于目前遇到的区间大小。
下面是这个想法在 JavaScript 中的实现:
function zeroSum(arr) {
let i = 0; // index in the input array, managed outside of recursion
// Longest zero-sum interval so far. Zero based, and value at end index
// is not part of the interval:
let longest = [0, 0];
function recur(dir) { // dir is the previous value from the array (if any)
let start = i; // local variable
while (i < arr.length) {
let val = arr[i++];
if (val == -dir) return true; // zero sum
if (recur(val) && i - start > longest[1] - longest[0]) {
longest[0] = start;
longest[1] = i;
}
}
return false; // no zero sum
}
recur(0); // 0 is passed to indicate there is no previous value
return longest;
}
// demo
console.log(zeroSum([1, 1, -1, 1, -1, -1, 1, -1]));