📌  相关文章
📜  在 O(n) 时间和 O(1) 额外空间内查找重复项 |设置 1

📅  最后修改于: 2022-05-13 01:57:51.929000             🧑  作者: Mango

在 O(n) 时间和 O(1) 额外空间内查找重复项 |设置 1

给定一个包含 n 个元素的数组,其中包含从 0 到 n-1 的元素,其中任何数字出现任意次数。在 O(n) 中找到这些重复的数字,并且只使用恒定的内存空间。

例子:

Input : n = 7 and array[] = {1, 2, 3, 6, 3, 6, 1}
Output: 1, 3, 6

Explanation: The numbers 1 , 3 and 6 appears more
than once in the array.

Input : n = 5 and array[] = {1, 2, 3, 4 ,3}
Output: 3

Explanation: The number 3 appears more than once
in the array.

此问题是以下问题的扩展版本。
查找给定数组中的两个重复元素
上述链接的方法 1 和方法 2 不适用,因为问题是 O(n) 时间复杂度和 O(1) 常数空间。此外,方法 3 和方法 4 不能在这里应用,因为在这个问题中可能有超过 2 个重复元素。可以扩展方法 5 以解决此问题。下面是类似于方法5的解决方案。

解决方案1:

  • 方法:数组中的元素从 0 到 n-1,并且都是正数。所以要找出重复的元素,需要一个HashMap,但问题是要解决常数空间的问题。有一个问题,数组的长度为 n,元素从 0 到 n-1(n 个元素)。该数组可以用作HashMap。
    以下方法中的问题。此方法仅适用于最多具有 2 个重复元素的数组,即如果数组包含超过 2 个元素的重复元素,它将不起作用。例如:{1, 6, 3, 1, 3, 6, 6} 它将输出为:1 3 6 6。
  • 注意:上述程序不处理 0 情况(如果数组中存在 0)。该程序也可以很容易地修改以处理该问题。它没有被处理以保持代码简单。 (程序可以修改为处理 0 情况,方法是在所有值上加上加一(+1)。也从答案中减去一并在代码中编写{ arr [abs(arr[i]) – 1] }

在下面的其他方法中,所讨论的解决方案仅打印一次重复元素。

  • 方法:基本思路是使用HashMap来解决问题。但是有一个问题,数组中的数字是从 0 到 n-1,输入数组的长度为 n。因此,输入数组可以用作 HashMap。在遍历数组时,如果遇到元素“a”,则将第 a%n 个元素的值增加 n。可以通过将第 a % n' 个元素除以 n 来检索频率。
  • 算法:
    1. 从头到尾遍历给定的数组。
    2. 对于数组中的每个元素,将 arr[i]%n'th 元素增加 n。
    3. 现在再次遍历数组并打印所有那些 arr[i]/n 大于 1 的索引 i。这保证了数字 n 已添加到该索引
    4. 这种方法有效,因为所有元素都在 0 到 n-1 的范围内,并且 arr[i] 只有在值“i”出现多次时才会大于 n。

执行:

C++
// C++ code to find
// duplicates in O(n) time
#include 
using namespace std;
 
int main()
{
    int numRay[] = { 0, 4, 3, 2, 7, 8, 2, 3, 1 };
    int arr_size = sizeof(numRay) / sizeof(numRay[0]);
    // count the frequency
    for (int i = 0; i < arr_size; i++) {
        numRay[numRay[i] % arr_size]
            = numRay[numRay[i] % arr_size] + arr_size;
    }
    cout << "The repeating elements are : " << endl;
    for (int i = 0; i < arr_size; i++) {
        if (numRay[i] >= arr_size * 2) {
            cout << i << " " << endl;
        }
    }
    return 0;
}
 
// This code is contributed by aditya kumar (adityakumar129)


C
// C++ code to find
// duplicates in O(n) time
 
#include 
 
int main()
{
 
    int numRay[] = { 0, 4, 3, 2, 7, 8, 2, 3, 1 };
    int arr_size = sizeof(numRay) / sizeof(numRay[0]);
   
   
    // count the frequency
    for (int i = 0; i < arr_size; i++) {
        numRay[numRay[i] % arr_size]
            = numRay[numRay[i] % arr_size] + arr_size;
    }
    printf("The repeating elements are : \n");
    for (int i = 0; i < arr_size; i++) {
        if (numRay[i] >= arr_size * 2) {
            printf("%d  \n", i );
        }
    }
    return 0;
}
// This code is contributed by aditya kumar (adityakumar129)


Java
// JAVA code to find
// duplicates in O(n) time
 
class Leet442 {
 
    public static void main(String args[])
    {
        int numRay[] = { 0, 4, 3, 2, 7, 8, 2, 3, 1 };
 
        for (int i = 0; i < numRay.length; i++) {
            numRay[numRay[i] % numRay.length]
                = numRay[numRay[i] % numRay.length]
                  + numRay.length;
        }
        System.out.println("The repeating elements are : ");
        for (int i = 0; i < numRay.length; i++) {
            if (numRay[i] >= numRay.length * 2) {
                System.out.println(i + " ");
            }
        }
    }
}


Python
# Python3 code to find duplicates in O(n) time
numRay = [0, 4, 3, 2, 7, 8, 2, 3, 1]
arr_size = len(numRay)
for i in range(arr_size):
 
    x = numRay[i] % arr_size
    numRay[x] = numRay[x] + arr_size
 
print("The repeating elements are : ")
for i in range(arr_size):
    if (numRay[i] >= arr_size*2):
        print(i, " ")
 
# This code is contributed by 29AjayKumar


C#
// C# code to find
// duplicates in O(n) time
using System;
class Leet442
{
    public static void Main(String []args)
    {
        int []numRay = { 0, 4, 3, 2, 7, 8, 2, 3, 1 };
 
        for (int i = 0; i < numRay.Length; i++)
        {
            numRay[numRay[i] % numRay.Length]
                = numRay[numRay[i] % numRay.Length]
                + numRay.Length;
        }
        Console.WriteLine("The repeating elements are : ");
        for (int i = 0; i < numRay.Length; i++)
        {
            if (numRay[i] >= numRay.Length * 2)
            {
                Console.WriteLine(i + " ");
            }
        }
    }
}
 
// This code is contributed by shivanisinghss2110


Javascript


输出:

The repeating elements are : 
2 
3

复杂性分析:

  • 时间复杂度: O(n)。
    只需要两次遍历。所以时间复杂度是O(n)。
  • 辅助空间: O(1)。
    不需要额外的空间,因此空间复杂度是恒定的。