Java 在常量空间中查找k个排序列表中的公共元素(假设它们可以有重复的值)

Java 在常量空间中查找k个排序列表中的公共元素(假设它们可以有重复的值),java,algorithm,Java,Algorithm,我想知道找到k个排序整数列表的交集(假设它们可以有重复项)最有效的解决方案是什么。我已经想出了一些解决办法。但我想知道是否有任何方法可以在恒定的空间和最佳的时间复杂度下实现这一点 Ex: for k=4 [[1,2,3,3,4],[2,3,3,5],[1,2,3,3,5,6,7],[1,2,3,3,6,7,8,9]] should return [2,3,3] 这里是一个通用算法,除了存储找到的公共元素外,它不需要任何额外的空间 Place pointers at the start of e

我想知道找到k个排序整数列表的交集(假设它们可以有重复项)最有效的解决方案是什么。我已经想出了一些解决办法。但我想知道是否有任何方法可以在恒定的空间和最佳的时间复杂度下实现这一点

Ex:
for k=4
[[1,2,3,3,4],[2,3,3,5],[1,2,3,3,5,6,7],[1,2,3,3,6,7,8,9]]
should return [2,3,3]

这里是一个通用算法,除了存储找到的公共元素外,它不需要任何额外的空间

Place pointers at the start of each of the N arrays

Then repeat the following
    Check if all N elements are the same
    If yes, then
        Advance all N pointers by one
    If no, then
        Advance only the pointer of the smallest value
    Repeat this until all elements have been exhausted

您可以使用映射来计算数组内容,然后检查哪些数字符合您的条件

    int[][] input = new int[][]{{1, 2, 3, 3, 4}, {2, 3, 3, 5}, {1, 2, 3, 3, 5, 6, 7}, {1, 2, 3, 3, 6, 7, 8, 9}};
    int k = 4;

    Map<Integer, Integer> counter = new HashMap<>();
    for (int[] oneArray : input) {
        for (int oneNumber : oneArray) {
            counter.merge(oneNumber, 1, (a, b) -> a + b);
        }
    }

    for (Map.Entry<Integer, Integer> countEntry : counter.entrySet()) {
        if (countEntry.getValue() % k == 0) {
            int numberOfHits = countEntry.getValue() / k;
            for (int kCount = 0; kCount < numberOfHits; kCount++) {
                System.out.println(countEntry.getKey());
            }
        }
    }
int[]]input=newint[][{{1,2,3,3,4},{2,3,3,5},{1,2,3,3,5,6,7},{1,2,3,3,6,7,8,9};
int k=4;
Map counter=newhashmap();
for(int[]oneArray:input){
for(int-oneNumber:oneArray){
计数器合并(oneNumber,1,(a,b)->a+b);
}
}
对于(Map.Entry countEntry:counter.entrySet()){
if(countEntry.getValue()%k==0){
int numberOfHits=countEntry.getValue()/k;
for(int-kCount=0;kCount
如果任何列表中的副本数量超过列表长度的一半,我们可以使用比最初给定的更少的空间来完成:)

将该列表转换为哈希映射,其中键是列表的元素,值是元组:
{count,intersection\u count,k\u count}


现在遍历其余列表:如果看到的元素是转换为哈希映射的列表中的一个键,则将
intersection\u count
设置为
min(当前列表中的count,intersection\u count)
并增加
k\u count
就地方法

您可以使用两个排序数组的稍微更改的就地合并算法来查找就地交点。我们将进行
N-1
N
是数组的数量)迭代。在每次迭代中,我们将第一个数组与索引为
i+1
的数组合并。结果将写入第一个数组。大概是这样的:

private static int intersect(int[]a,int[]alen,int[]b){
int resLen=0,bIndex=0;
对于(int-aIndex=0;aIndexb[bIndex])++bIndex;
如果(bIndex==b.长度)中断;
如果(a[aIndex]==b[bIndex]){
a[resLen]=a[aIndex];
++雷斯伦;
++宾得;
}
}
返回resLen;
}
专用静态int数组(int[][]数组){
int len=数组[0]。长度;
对于(int i=1;i
因此,我们有恒定的额外空间和线性时间复杂性

另一种方法

如果我们不能改变输入,我们可以使用另一种算法

首先,让我们取第一个数组的第一个数字(
current

然后,对于每个数组,我们可以在数组中找到此<代码>当前编号的出现次数(这可以通过两个二进制搜索完成)。然后输出这个数字“最小发生次数”

然后,我们将在第一个数组中找到下一个数字(大于上一个数字)(同样使用二进制搜索),依此类推


此算法的时间复杂度将取决于第一个数组中不同值的数量(
D
)。它将等于
O(D*N*logK)
,其中K-数组的最大长度。值得注意的是,在某些情况下,此算法可能比上面的就地算法快得多

尝试将每个数据列表存储为集合或多集合,而不是列表。集合有一种内置的、高效的方法来查找集合的交集。

您想要实际代码还是只需要算法的描述?交集是否必须是连续的?例:如果[1,2,3,4,5]和[1,2,2,3,4],那么[2,3,4]或[1,2,3,4]?@Tim Biegeleisen Java代码会更好。square1001是否继续无关紧要在您的示例中,答案应该是[1,2,3,4],它如何触及每个元素一次?假设N个元素中的某些元素(但不是全部)相同。现在我们推进最小元素。我们将新元素与之前检查过的元素进行比较的元素有多少?(还有,你如何发现哪种元素现在是最小的?)。。。当然,您可以使用堆…在java中,您需要将这些指针存储在一个数组中,这意味着您的空间复杂度将是O(K),这似乎是正确的,但是更改输入是否可以?我们在第一个数组中存储合并数组的事实是否使它成为常数空间算法?在这种情况下,时间复杂度是O(KN)?K#数组N#每个数组的长度?@sepi如果我们不能更改输入,就不可能获得恒定的空间,因为我们需要额外的内存来存储结果,而结果不是恒定的。时间复杂度为O(n),其中n是数组长度之和。如果它们都有相同的长度K,那么,是的,O(N*K)。@sepi“我们在第一个数组中存储合并数组的事实是否使其成为常数空间算法?”是的,是的。谢谢你的回答。我知道我们需要使用内存来返回结果,这不被认为是额外的空间。例如,我不确定在面试期间是否允许我们更改输入。我认为有一种使用二进制搜索的解决方案,但时间复杂度会高得多@•㪞דברקן其他列表中不存在的第一个列表中的值呢?在这种情况下,最终的映射也会包含这些值。它不会继续
private static int intersect(int[] a, int alen, int[] b) {
    int resLen = 0, bIndex = 0;
    for (int aIndex = 0; aIndex < alen; ++aIndex) {
        while (bIndex < b.length && a[aIndex] > b[bIndex]) ++bIndex;
        if (bIndex == b.length) break;

        if (a[aIndex] == b[bIndex]) {
            a[resLen] = a[aIndex];
            ++resLen;
            ++bIndex;
        }
    }
    return resLen;
}

private static int intersectArrays(int[][] arrays) {
    int len = arrays[0].length;
    for (int i = 1; i < arrays.length; ++i) {
        len = intersect(arrays[0], len, arrays[i]);
    }
    return len;
}

public static void main (String[] args) throws java.lang.Exception
{
    int[][] arr = {{1,2,3,3,4},{2,3,3,5},{1,2,3,3,5,6,7},{1,2,3,3,6,7,8,9}};
    int len = intersectArrays(arr);
    for (int i = 0; i < len; ++i)
        System.out.print(arr[0][i] + " ");
}