我有n
个数组,每个数组都包含任意数量的整数。数组中不可能有重复项([1,1,2]
不能成为n
数组之一。)
我还有一个大小为m
的整数数组,其中填充了从1
到m
的整数(value_of_an_array_entry = array_index + 1)。示例:m = 4
,相应的数组为[1,2,3,4]
。
我的问题:
对于给定的n
和m
,是否可以通过从每个m
数组中挑选最多1个元素来查找n
数组中的每个元素?
一个例子:
n = 3, m = 3,
n
数组:[1]
,[1, 2]
,[2, 3]
输出应为:Yes
(因为我们可以通过从每个m
数组中挑选最多1个元素来查找n
数组中的每个元素。查看n
数组并选择{{1来自第一个数组,来自第二个数组的1
和来自第三个数组的2
。)
这是一个面试问题,我收到了一个关于Max流量问题的提示(我不知道这对我有什么帮助)。
答案 0 :(得分:8)
您可以构建如下图形:图形分为左侧部分和右侧部分。左侧部分包含n
个顶点,代表n
数组。右侧部分包含m
个顶点,代表m
个数字。
然后我们考虑这些n
数组。如果元素k
包含在i
- 数组中,我们在左边的i
个顶点和右边的k
个顶点之间绘制一条边。我们的目标是选择m
边,以便右侧的每个m
顶点都被m
边缘恰好覆盖一次,而左边的顶点最多被覆盖一次。这是一个二分图最大匹配问题,可以通过许多算法解决,包括最大流量。
答案 1 :(得分:1)
我认为递归方法应该这样做。
m' = tail(m)
和n' = other members of (n)
我没有测试过这个,但是:
public boolean check(List<Integer> m, List<List<Integer>> n) {
if (m.isEmpty()) {
return true;
}
int head = head(m);
List<Integer> tail = tail(m);
for (List<Integer> nMember : n) {
if (nMember.contains(head) && check(tail, nMinus(n, nMember))) {
return true;
}
}
return false;
}
假设方法:
head()
返回传递列表的第一个元素。tail()
返回已删除第一个元素的传递列表。nMinus()
会返回已移除n
的{{1}}的视图或副本。它不应该修改nMember
。您应该使用不可变集合,或者至少将它们视为不可变集合。 Guava提供了可能有用的类。但是你可以非常简单地敲定一个n
列表包装类,用它来实现没有Guava的ListOmitting
。
我不能肯定地说它不是太暴力,但它对于我的采访答案“感觉”足够有效。