在 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 来检索频率。
- 算法:
- 从头到尾遍历给定的数组。
- 对于数组中的每个元素,将 arr[i]%n'th 元素增加 n。
- 现在再次遍历数组并打印所有那些 arr[i]/n 大于 1 的索引 i。这保证了数字 n 已添加到该索引
- 这种方法有效,因为所有元素都在 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)。
不需要额外的空间,因此空间复杂度是恒定的。