如果可以删除任何一个元素,则查找数组是不是可以分为两个等和的子数组
Posted
技术标签:
【中文标题】如果可以删除任何一个元素,则查找数组是不是可以分为两个等和的子数组【英文标题】:Find if array can be divided into two subarrays of equal sum if any one element can be deleted如果可以删除任何一个元素,则查找数组是否可以分为两个等和的子数组 【发布时间】:2021-10-11 12:00:44 【问题描述】:给定一个数字数组,查找是否有一种方法可以从数组中删除/删除一个数字并在数组中进行一个分区(将数组分成两个子数组),使得 subarray1 中的元素之和等于subarray2 中的元素。
A subarray is a contiguous part of array.
Array [1, 2, 3, 4] has (1), (1,2), (2,3,4),(1,2,3,4) etc.. as its subarrays but not (1,3) , (2,4) , (1,3,4), etc..
现在让我们考虑一个例子:-
(Follow 0-based indexing )
Array[] = [ 6, 2, 2, 1, 3 ]
Possible solutions
Delete Array[0] => updated array: - [ 2,2,1,3 ]
Possible partition : - [2,2] and [3,1] where (2+2) = (3+1) = 4
or
Delete Array[1] => updated array: - [ 6,2,1,3 ]
Possible partition : - [6] and [2,1,3] where (6) = (2+1+3) = 6
or
Delete Array[2] => updated array: - [ 6,2,1,3 ]
Possible partition : - [6] and [2,1,3] where (6) = (2+1+3) = 6
现在已经存在一个类似的问题,我们只需要找到数组是否可以分为两个相等 sum 的子数组,可以在 O(n) =>
PsuedoCode:- 有效的解决方案涉及计算所有的总和 数组的元素提前。然后对于数组的每个元素, 我们可以通过使用总和在 O(1) 时间内计算它的正确和 数组元素减去到目前为止找到的元素的总和。时间复杂度 该解决方案的 O(n) 将是 O(n) 并且它使用的辅助空间将是 O(1)。
因此,要解决我们的问题,一种蛮力方法是:- 删除每个元素一次并检查数组是否可以分成两个相等和的子数组。因此它将需要 O(n^2) 时间。
那么我们能比这个时间复杂度做得更好吗?
【问题讨论】:
支点在哪里,输入的答案是什么,[10, -1, 1]?换句话说,分区的一侧可以没有元素吗? 两个分区必须至少包含一个元素。因此,对于您的示例,将不存在枢轴,我们可以返回 -1...只是想知道即使我们可以将任何一个分区保持为零,原始问题的“最佳方法”也可以修改以适应这一点,不是吗?跨度> 【参考方案1】:您可以使用地图来跟踪数组中每个值出现的位置。然后,当您在考虑每个分区点的情况下通过数组时,如果地图中存在左右两半之间的差异,并且在正确的一半(通过比较左右差异与位置是正还是负来确定)相对于当前分区点的值),那么您就有了解决方案。
这里有一些 Java 代码来说明:
static boolean splitDelete(int[] a)
Map<Integer, List<Integer>> map = new HashMap<>();
for(int i=0; i<a.length; i++)
List<Integer> idx = map.get(a[i]);
if(idx == null) map.put(a[i], idx = new ArrayList<>());
idx.add(i);
int sum = 0;
for(int v : a) sum += v;
int diff = sum;
for(int i=0; i<a.length-1; i++)
diff -= 2*a[i];
if(map.containsKey(Math.abs(diff)))
for(int j : map.get(Math.abs(diff)))
if(diff > 0 == j > i) return true;
return false;
【讨论】:
我添加了一个我认为与您的答案相似的答案,只是它不存储所见元素的索引。对于for(int j
循环为 O(n) 的输入,您的答案的复杂性是多少?【参考方案2】:
作为 RaffleBuffle pointed out,当我们遍历不同的分离点时,可能会有一些被删除元素的场景。例如,
a a a a a a a a a a a a a a
<-----X--------->|<------->
a a a a a a a a a a a a a a
<--------------->|<---X--->
以 O(n) 的整体复杂度解决它的一种方法是遍历两次。每次检查两个总和之间的差异是否在我们一直在跟踪的值映射中。
Python 代码:
def f(A):
values = set()
total_sum = sum(A)
# Traverse from left, each part
# must have at least one element.
left_sum = A[0]
right_sum = total_sum - A[0]
values.add(A[0])
for i in range(1, len(A) - 1):
values.add(A[i])
left_sum += A[i]
right_sum -= A[i]
# We have an element in the left part
# that's the difference between left
# and right sums.
if (left_sum - right_sum) in values:
return True
# Traverse from right, each part
# must have at least one element.
right_sum = A[len(A)-1]
left_sum = total_sum - A[len(A)-1]
values.clear()
values.add(A[len(A)-1])
for i in range(len(A) - 2, 0, -1):
values.add(A[i])
right_sum += A[i]
left_sum -= A[i]
# We have an element in the right part
# that's the difference between right
# and left sums.
if (right_sum - left_sum) in values:
return True
return False
As = [
[1, 2, 1, 1, 1], # True
[1, 1, 1, 2, 1], # True
[1, 1, 1, 1, 1, 1], # False
[6, 2, 2, 1, 3] # True
]
for A in As:
print("%s\n%s\n\n" % (A, f(A)))
【讨论】:
以上是关于如果可以删除任何一个元素,则查找数组是不是可以分为两个等和的子数组的主要内容,如果未能解决你的问题,请参考以下文章