Java 在时间复杂度O(n)和空间复杂度O(1)的数组中查找重复元素的最有效算法是什么?
注意-您不能使用集合或映射 我已经试过了,但它没有复杂性O(n)Java 在时间复杂度O(n)和空间复杂度O(1)的数组中查找重复元素的最有效算法是什么?,java,data-structures,Java,Data Structures,注意-您不能使用集合或映射 我已经试过了,但它没有复杂性O(n) 类元素 { 无效打印重复(整数arr[],整数大小) { int i,j; System.out.println(“重复元素为:”); 对于(i=0;i
类元素
{
无效打印重复(整数arr[],整数大小)
{
int i,j;
System.out.println(“重复元素为:”);
对于(i=0;i
是否有任何一个解决方案,可以在不使用集合或映射的情况下找到一个重复的数组,并且只使用单for循环确定,因此您对
int
类型的数组有一个恒定的内存需求?没问题,让我们使用一个大的(但恒定的)
byte
数组:
byte[] seen = new byte[536870912];
byte[] dups = new byte[536870912];
for (int i : arr) {
int idx = i / 8 + 268435456;
int mask = 1 << (i % 8);
if ((seen[idx] & mask) != 0) {
if ((dups[idx] & mask) == 0) {
System.out.print(i + " ");
dups[idx] |= mask;
}
} else {
seen[idx] |= mask;
}
}
byte[]seen=新字节[536870912];
字节[]dups=新字节[536870912];
用于(int i:arr){
int idx=i/8+268435456;
int mask=1由于它们是int
s,您可以使用位集
:
void printRepeating(int arr[], int size) {
BitSet bits = new BitSet();
BitSet repeated = new BitSet();
//to deal with negative ints:
BitSet negativeBits = new BitSet();
BitSet negativeRepeatedBits = new BitSet();
for(int i : arr) {
if(i<0) {
i = -i; //use the absolute value
if(negativeBits.get(i)) {
//this is a repeat
negativeRepeatedBits.set(i);
}
negativeBits.set(i);
} else {
if(bits.get(i)) {
//this is a repeat
repeated.set(i);
}
bits.set(i);
}
}
System.out.println(
IntStream.concat(negativeRepeatedBits.stream().map(i -> -i), repeated.stream())
.mapToObj(String::valueOf)
.collect(Collectors.joining(", ", "Repated Elements are : ", ""))
);
}
void打印重复(int-arr[],int-size){
位集位=新位集();
重复的位集=新的位集();
//要处理负整数,请执行以下操作:
BitSet NegativeEBITs=新的位集();
比特集negativeRepeatedBits=新比特集();
用于(int i:arr){
if(i-i),repeated.stream())
.mapToObj(字符串::valueOf)
.collect(收集器。连接(“,”,“repatted”元素为:“,”))
);
}
请注意(根据注释)负值需要单独处理,否则,如果大小为n
的数组中的元素在0~n-1
的范围内(或1~n
),您可能会遇到indexootfboundsexception
我们可以尝试通过将a[i]
放入索引i
来对数组进行排序,对于每个a[i]!=i
,如果我们发现索引i
处已经有一个a[i]
,这意味着有另一个值为a[i]
的元素
for (int i = 0; i < a.length; i++){
while (a[i] != i) {
if (a[i] == a[a[i]]) {
System.out.print(a[i]);
break;
} else {
int temp = a[i]; // Putting a[i] to index i by swapping them
a[i] = a[a[i]];
a[temp] = temp;
}
}
}
for(int i=0;i
因为在每次交换之后,其中一个元素将处于正确的位置,因此最多会有n次交换操作
时间复杂度O(n)
空间复杂度O(1)对于循环只有一个,i
将在j
位于数组末尾时增加,在找到新的重复元素之前找到当前的arr[i]
void printRepeatingSingleLoop(int arr[], int size)
{
int i, j, k;
System.out.println("Repeated Elements are :");
for (i = 0, j = 1, k = 0; i < size; )
{
if (k < i ) {
if (arr[i] == arr[k]) {
i++;
j = i+1;
k = 0;
} else {
k++;
}
} else {
if (j == size) {
i++;
j = i + 1;
k = 0;
} else {
if (arr[i] == arr[j]) {
System.out.print(arr[i] + " ");
i++;
j = i + 1;
k = 0;
} else {
j++;
}
}
}
}
System.out.println();
}
void printing repeatingsingleloop(int arr[],int size)
{
int i,j,k;
System.out.println(“重复元素为:”);
对于(i=0,j=1,k=0;i
关键是使用集合。检查这个问题:我已经指示我们不能使用集合,并且只会使用一个for循环used@pedrohreis我不这么认为,因为据我所知,OP不允许使用集合
和集合
s实现集合
。。如果你说的是映射
s,你是正确的。你能对数组包含的内容进行任何计算吗?一种空间效率非常低的方法是创建一个布尔标记数组,如果该数字之前是否找到过。对于输入中的每个元素,你检查数组中的标志是否为真;如果是,则重复元素,否则将位置标记为已访问。然而r、 这看起来真的很像家庭作业,在现实生活中你会使用一套方法谢谢你的贡献,如果还有其他方法,我想知道,不使用byte[]seen=new byte[536870912]这是你应得的一票,但我没有多少报告可投you@Johanes它工作得很好,但是为什么我们要使用常量字节数组,如果元素是以十亿为单位的大数字,那么会发生什么呢?它是一个常量。请再次阅读如何使用大O表示法,什么是渐近复杂性,以及为什么常量不重要。@JimMischel也许我不是这不是很好的字里行间阅读。In说他们不知道范围。如果你有其他信息,请编辑问题并将这些详细信息添加到中。虽然使用位集似乎是正确的做法,但它是正确的。感谢@JohannesKuhn指出这一点。我已编辑以解决该陷阱。几乎正确。OP想要打印所有重复元素,因此在a[i]==a[a[i]
的情况下,您将希望中断
,而不是返回
。如果有两个以上的重复项,则您的代码无法正常工作
void printRepeatingSingleLoop(int arr[], int size)
{
int i, j, k;
System.out.println("Repeated Elements are :");
for (i = 0, j = 1, k = 0; i < size; )
{
if (k < i ) {
if (arr[i] == arr[k]) {
i++;
j = i+1;
k = 0;
} else {
k++;
}
} else {
if (j == size) {
i++;
j = i + 1;
k = 0;
} else {
if (arr[i] == arr[j]) {
System.out.print(arr[i] + " ");
i++;
j = i + 1;
k = 0;
} else {
j++;
}
}
}
}
System.out.println();
}