Find a duplicate element in an array

本文介绍了一种在不使用辅助存储空间的情况下查找已知范围内的重复整数的方法。通过求和与位运算两种方式实现,避免了数据溢出的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Question:

Suppose you have an array of 1001 integers. The integers are in random order, but you know each of the integers is between 1 and 1000 (inclusive). In addition, each number appears only once in the array, except for one number, which occurs twice. Assume that you can access each element of the array only once. Describe an algorithm to find the repeated number. If you used auxiliary storage in your algorithm, can you find an algorithm that does not require it?

 

如果可以用辅助空间的话,可以用HashSet来处理,如果add失败说明有重复的。但是如果不能用额外空间的话呢?

 

Solution 1:

考虑加法。1+2+...+n = n(n-1)/2

假设数组所有元素之和为sum, 那么sum-n(n-1)/2就是我们要找的重复的数。

public int findDuplicate(int[] nums) {
	int sum = 0;
	int n = nums.length;
	int expected = n*(n-1)/2;
	for(int i=0; i<n; i++) {
		sum += nums[i];
	}
	return sum-expected;
}

但是数组的元素数达到或接近INT_MAX的时候, 加法运算就会溢出。我们还可以考虑位运算XOR。

XOR具有以下性质:

交换律A \oplus B = B \oplus A

结合律A \oplus (B \oplus C)=(A \oplus B) \oplus C

恒等律X\oplus 0=X

归零律X\oplus X=0

自反A \oplus B \oplus B=A\oplus 0=A

假设给定数组A[6] = {5,2,3,4,3,1},而我们期望的数组应该为A[6]={0,1,2,3,4,5}。其中我们用0来代替重复的元素。

接下来对给定数组和我们期望数组的所有元素做异或运算:

(5^0)^(2^1)^(3^2)^(4^3)^(3^4)^(1^5)

= (5^5)^(2^2)^(3^3)^(4^4)^(1^1)^(3^0)

= 0^3

= 3

写成代码则非常简单。

Solution2:

public int findDuplicate(int[] nums) {
	int dup = 0;
	for(int i=0; i<nums.length; i++) {
		dup ^= nums[i]^i;
	}
	return dup;
}

Reference:

http://stackoverflow.com/questions/2605766/how-to-find-a-duplicate-element-in-an-array-of-shuffled-consecutive-integers 

``` package oy.tol.tra; import java.util.List; import java.util.Objects; /** * A generic and slow Key-Value linear array. */ public class KeyValueArray<K extends Comparable<K>, V> implements Dictionary<K,V> { private Pair<K, V> [] pairs = null; private int count = 0; private int reallocationCount = 0; public KeyValueArray(int capacity) { ensureCapacity(capacity); } public KeyValueArray() { ensureCapacity(20); } @Override public Type getType() { return Type.SLOW; } @SuppressWarnings("unchecked") @Override public void ensureCapacity(int size) throws OutOfMemoryError { if (size < 20) { size = 20; } pairs = (Pair<K,V>[])new Pair[size]; reallocationCount = 0; } @Override public int size() { return count; } @Override public String getStatus() { String toReturn = "KeyValueArray reallocated " + reallocationCount + " times, each time doubles the size\n"; toReturn += String.format("KeyValueArray fill rate is %.2f%%%n", (count / (double)pairs.length) * 100.0); return toReturn; } @Override public boolean add(K key, V value) throws IllegalArgumentException, OutOfMemoryError { if (null == key || value == null) throw new IllegalArgumentException("Person or phone number cannot be null"); for (Pair<K, V> pair : pairs) { // Must not have duplicate keys, so check if key is already in the array. if (pair != null && pair.getKey().equals(key)) { pair.setValue(value); return true; } } if (count >= pairs.length) { reallocate(pairs.length * 2); } if (count < pairs.length) { pairs[count++] = new Pair<>(key, value); return true; } return false; } @Override public V find(K key) throws IllegalArgumentException { if (null == key) throw new IllegalArgumentException("Person to find cannot be null"); for (int counter = 0; counter < count; counter++) { if (pairs[counter] != null && key.equals(pairs[counter].getKey())) { return pairs[counter].getValue(); } } return null; } @Override @java.lang.SuppressWarnings({"unchecked"}) public Pair<K,V> [] toSortedArray() { Pair<K, V> [] sorted = (Pair<K,V>[])new Pair[count]; int newIndex = 0; for (int index = 0; index < count; index++) { if (pairs[index] != null) { sorted[newIndex++] = new Pair<>(pairs[index].getKey(), pairs[index].getValue()); } } Algorithms.fastSort(sorted); return sorted; } @Override public void compress() throws OutOfMemoryError { // Partition nulls to the end of the array int indexOfFirstNull = Algorithms.partition(pairs, count, element -> element == null); // Reallocate to the size of non-null elements reallocate(indexOfFirstNull); } @java.lang.SuppressWarnings("unchecked") private void reallocate(int newSize) throws OutOfMemoryError { reallocationCount++; Pair<K, V> [] newPairs = (Pair<K,V>[])new Pair[newSize]; for (int index = 0; index < count; index++) { newPairs[index] = pairs[index]; } pairs = newPairs; } }```testSlowArray有问题
最新发布
03-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值