Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在大小为N的整数数组中查找总和为X的对,该数组的元素范围为0到N-1_Arrays_Algorithm_Sorting - Fatal编程技术网

Arrays 在大小为N的整数数组中查找总和为X的对,该数组的元素范围为0到N-1

Arrays 在大小为N的整数数组中查找总和为X的对,该数组的元素范围为0到N-1,arrays,algorithm,sorting,Arrays,Algorithm,Sorting,这是一个面试问题。我们有一个大小为N的整数数组,包含0到N-1之间的元素。一个数字可能出现两次以上。目标是找到总和为给定数字X的对 我使用了一个辅助数组,该数组包含主数组的元素数,然后根据辅助数组重新排列主数组,以便对主数组进行排序,然后搜索对 但面试官希望空间复杂度保持不变,所以我告诉他对数组进行排序,但这是一个非对数时间复杂度的解决方案。他想要O(n)解决方案 有没有什么方法可以在没有任何额外空间的情况下用O(n)来做这件事?没有,我不这么认为。您或者需要额外的空间,以便能够通过分配给buc

这是一个面试问题。我们有一个大小为N的整数数组,包含0到N-1之间的元素。一个数字可能出现两次以上。目标是找到总和为给定数字X的对

我使用了一个辅助数组,该数组包含主数组的元素数,然后根据辅助数组重新排列主数组,以便对主数组进行排序,然后搜索对

但面试官希望空间复杂度保持不变,所以我告诉他对数组进行排序,但这是一个非对数时间复杂度的解决方案。他想要O(n)解决方案


有没有什么方法可以在没有任何额外空间的情况下用O(n)来做这件事?

没有,我不这么认为。您或者需要额外的空间,以便能够通过分配给bucket来“排序”O(n)中的数据,或者需要在不属于O(n)的位置进行排序


当然,如果你能做出某些假设,总有一些技巧。例如,如果
N<64K
且整数为32位宽,则可以在当前数组的顶部复用计数数组所需的空间

换句话说,使用较低的16位存储数组中的值,然后使用较高的16位存储与索引匹配的值的计数

让我们使用一个简化的示例,其中
N==8
。因此,数组长度为8个元素,每个元素的整数都小于8,尽管它们是8位宽。这意味着(最初)每个元素的前四位为零

  0    1    2    3    4    5    6    7    <- index
(0)7 (0)6 (0)2 (0)5 (0)3 (0)3 (0)7 (0)7

例如,考虑存储7的第一个索引。因此,该赋值语句将在索引7中添加16,增加7的计数。模运算符用于确保已增加的值仅使用较低的四位来指定数组索引

因此,阵列最终变成:

  0    1    2    3    4    5    6    7    <- index
(0)7 (0)6 (1)2 (2)5 (0)3 (1)3 (1)7 (3)7
基本上,你要做的是一步一步地遍历数组,得到总数为8的数字的乘积

  • 对于0,您需要添加8(它不存在)
  • 对于1,您需要添加7。计数的乘积是0 x 3,因此没有任何结果
  • 对于2,您需要添加6。计数的乘积为1 x 1,因此出现一次
    (2,6)
  • 对于3,您需要添加5。计数的乘积为2 x 1,因此出现两次
    (3,5)
  • 对于4,这是一个特例,因为你不能使用该产品。在这种情况下,这并不重要,因为没有4s,但如果有4s,就不能成为一对。当您配对的数字相同时,公式是(假设有
    m
    个)
    1+2+3+…+m-1
    。用一点数学知识,结果是
    m(m-1)/2
除此之外,您正在与左边的值配对,您已经这样做了,因此您将停止

那么,你从中得到了什么

a b c d e f g h <- identifiers
7 6 2 5 3 3 7 7

而且,如果检查输入数字,您会发现对是正确的。

这可以通过在O(N)时间内将输入数组转换为“就地”计数器列表来完成。当然,这假设输入数组不是不变的。不需要对每个数组元素中未使用的位进行任何额外的假设

从以下预处理开始:尝试将每个数组的元素移动到由元素值确定的位置;将该位置上的元素也移动到由其值确定的位置;继续,直到:

  • 下一个元素被移动到该循环开始的位置
  • 无法移动下一个元素,因为它已位于与其值对应的位置(在本例中,将当前元素放置到该循环开始的位置)
预处理后,每个元件要么位于其“适当”位置,要么指向其“适当”位置。如果每个元素中有一个未使用的位,我们可以将每个正确定位的元素转换为计数器,用“1”初始化它,并允许每个“定点”元素增加适当的计数器。附加位允许区分计数器和值。同样的事情也可以不用任何额外的比特,但使用较少的算法

计算数组中的值如何等于0或1。如果存在任何此类值,将其重置为零,并更新位置0和/或1处的计数器。设置
k=2
(值小于
k
的数组部分的大小由计数器替换)。对k=2、4、8……应用以下程序

  • 在位置
    k.处查找元素。。2k-1
    处于“正确”位置的,用计数器替换,初始值为“1”
  • 对于位于
    k。。2k-1
    带值
    2。。k-1
    更新位置
    2.处的相应计数器。。k-1
    并将值重置为零
  • 对于位于
    0。。2k-1
    带值
    k。。2k-1
    更新位置
    k.处的相应计数器。。2k-1
    并将值重置为零
  • 该过程的所有迭代加在一起具有O(N)时间复杂度。最后,输入数组完全转换为计数器数组。这里唯一的困难是在
    0.位置最多有两个计数器。。2k-1
    的值可能大于
    k-1
    。但这可以通过为每个索引存储两个附加索引并将这些索引处的元素作为计数器而不是值来缓解


    生成计数器数组后,我们可以将计数器对相乘(其中对应的索引对总和为
    X
    )以获得所需的对计数。

    字符串排序是n log n,但是如果您可以假设数字是有界的(您可以这样做,因为您只对总和为特定值的数字感兴趣)可以使用基数排序。基数排序取O(kN)
     0   1   2   3   4   5   6   7    <- index
    (0) (0) (1) (2) (0) (1) (1) (3)
    
    a b c d e f g h <- identifiers
    7 6 2 5 3 3 7 7
    
    (2,6) (3,5) (3,5)
    (c,b) (e,d) (f,d) <- identifiers
    
    #include <stdio.h>
    
    int arr[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 4, 4, 4, 4};
    #define SZ (sizeof(arr) / sizeof(*arr))
    
    static void dumpArr (char *desc) {
        int i;
        printf ("%s:\n   Indexes:", desc);
        for (i = 0; i < SZ; i++) printf (" %2d", i);
    
        printf ("\n   Counts :");
        for (i = 0; i < SZ; i++) printf (" %2d", arr[i] / 100);
    
        printf ("\n   Values :");
        for (i = 0; i < SZ; i++) printf (" %2d", arr[i] % 100);
    
        puts ("\n=====\n");
    }
    
    int main (void) {
        int i, j, find, prod;
    
        dumpArr ("Initial");
    
        // Sort array in O(1) - bucket sort.
    
        for (i = 0; i < SZ; i++) {
            arr[arr[i] % 100] += 100;
        }
    
        dumpArr ("After bucket sort");
    
        // Now do pairings.
    
        find = 8;
        for (i = 0, j = find - i; i <= j; i++, j--) {
            if (i == j) {
                prod = (arr[i]/100) * (arr[i]/100-1) / 2;
                if (prod > 0) {
                    printf ("(%d,%d) %d time(s)\n", i, j, prod);
                }
            } else {
                if ((j >= 0) && (j < SZ)) {
                    prod = (arr[i]/100) * (arr[j]/100);
                    if (prod > 0) {
                        printf ("(%d,%d) %d time(s)\n", i, j, prod);
                    }
                }
            }
        }
    
        return 0;
    }
    
    Initial:
       Indexes:  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
       Counts :  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
       Values :  3  1  4  1  5  9  2  6  5  3  5  8  9  4  4  4  4
    =====
    
    After bucket sort:
       Indexes:  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
       Counts :  0  2  1  2  5  3  1  0  1  2  0  0  0  0  0  0  0
       Values :  3  1  4  1  5  9  2  6  5  3  5  8  9  4  4  4  4
    =====
    
    (2,6) 1 time(s)
    (3,5) 6 time(s)
    (4,4) 10 time(s)