Java查找一个数组中缺少的数,在数字数组中查找缺失数字的最快方法

假设给定的数组为A,长度为N。假设在给定的数组中,单个空插槽填充为0。

我们可以使用多种方法(包括在中使用的算法)找到该问题的解决方案Counting sort。但是,就有效的时间和空间使用而言,我们有两种算法。一种主要使用求和,减法和乘法。另一个使用XOR。从数学上讲,这两种方法都可以正常工作。但是以编程方式,我们需要使用以下主要措施评估所有算法:

局限性(例如输入值大(A[1...N])和/或输入值个数大(N))

涉及条件检查的次数

涉及的数学运算的数量和类型

这是由于时间和/或硬件(硬件资源限制)和/或软件(操作系统限制,编程语言限制等)的限制而引起的。让我们列出并评估它们各自的优缺点。 。

算法1:

在算法1中,我们有3种实现。

使用数学公式(1+2+3+...+N=(N(N+1))/2)计算所有数字的总和(包括未知的遗漏数字)。在这里,N=100。计算所有给定数字的总和。从第一个结果中减去第二个结果将得出缺失的数字。

Missing Number = (N(N+1))/2) - (A[1]+A[2]+...+A[100])

使用数学公式(1+2+3+...+N=(N(N+1))/2)计算所有数字的总和(包括未知的遗漏数字)。在这里,N=100。从该结果中减去每个给定的数字即可得出缺失的数字。

Missing Number = (N(N+1))/2)-A[1]-A[2]-...-A[100]

(Note:尽管第二个实现的公式是从第一个实现的公式得出的,但从数学角度来看两者都是相同的。但是从编程的观点来看,两者都是不同的,因为第一个实现的公式比第二个实现的公式更容易发生位溢出(如果给定的数字即使加法的速度比减法的速度还快,但是第二种实现减少了由大值的加法导致的位溢出的机会(它并未完全消除,因为N+1公式中存在()的机会仍然很小)但是,两者都容易因乘法而发生位溢出。其局限性在于,两个实现仅在时才给出正确的结果N(N+1)<=MAXIMUM_NUMBER_VALUE。对于第一个实现,另外的局限是仅当Sum of all given numbers<=MAXIMUM_NUMBER_VALUE。)时才给出正确的结果。

计算所有数字的总和(包括未知的遗漏数字),并在同一循环中并行减去每个给定数字。这样就消除了因乘法而导致位溢出的风险,但易于因加法和减法而导致位溢出。

//ALGORITHM

missingNumber = 0;

foreach(index from 1 to N)

{

missingNumber = missingNumber + index;

//Since, the empty slot is filled with 0,

//this extra condition which is executed for N times is not required.

//But for the sake of understanding of algorithm purpose lets put it.

if (inputArray[index] != 0)

missingNumber = missingNumber - inputArray[index];

}

在一种编程语言(如C,C ++,Java等)中,如果表示整数数据类型的位数受到限制,则上述所有实现都会由于求和,减法和乘法而易于发生位溢出,从而导致错误的结果如果输入值(A[1...N])大和/或输入值(N)大。

算法2:

我们可以使用XOR的属性来获取此问题的解决方案,而不必担心位溢出的问题。而且XOR比求和既安全又快速。我们知道XOR的性质,即两个相同数字的XOR等于0(A XOR A = 0)。如果我们计算从1到N的所有数字的XOR(这包括未知的丢失数字),然后得出结果,将所有给定的数字进行XOR运算(因为A XOR A=0)被抵消,最后得到丢失的数字数。如果没有位溢出问题,则可以使用求和和基于XOR的算法来获取解决方案。但是,使用XOR的算法比使用求和,减法和乘法的算法既安全又快速。而且我们可以避免加法,减法和乘法所带来的额外麻烦。

在算法1的所有实现中,我们可以使用XOR代替加法和减法。

假设 XOR(1...N) = XOR of all numbers from 1 to N

实现1 => Missing Number = XOR(1...N) XOR (A[1] XOR A[2] XOR...XOR A[100])

实现2 => Missing Number = XOR(1...N) XOR A[1] XOR A[2] XOR...XOR A[100]

实现3 =>

//ALGORITHM

missingNumber = 0;

foreach(index from 1 to N)

{

missingNumber = missingNumber XOR index;

//Since, the empty slot is filled with 0,

//this extra condition which is executed for N times is not required.

//But for the sake of understanding of algorithm purpose lets put it.

if (inputArray[index] != 0)

missingNumber = missingNumber XOR inputArray[index];

}

算法2的所有三种实现都可以正常工作(从编程的角度来看)。一种优化是,类似于

1+2+....+N = (N(N+1))/2

我们有,

1 XOR 2 XOR .... XOR N = {N if REMAINDER(N/4)=0, 1 if REMAINDER(N/4)=1, N+1 if REMAINDER(N/4)=2, 0 if REMAINDER(N/4)=3}

我们可以通过数学归纳法证明这一点。因此,我们可以使用此公式来减少XOR运算的数量,而不是通过对所有从1到N的数字进行XOR计算XOR(1 ... N)的值。

另外,使用上述公式计算XOR(1 ... N)具有两种实现。实施明智,计算

// Thanks to https://a3nm.net/blog/xor.html for this implementation

xor = (n>>1)&1 ^ (((n&1)>0)?1:n)

比计算快

xor = (n % 4 == 0) ? n : (n % 4 == 1) ? 1 : (n % 4 == 2) ? n + 1 : 0;

因此,优化的Java代码是

long n = 100;

long a[] = new long[n];

//XOR of all numbers from 1 to n

// n%4 == 0 ---> n

// n%4 == 1 ---> 1

// n%4 == 2 ---> n + 1

// n%4 == 3 ---> 0

//Slower way of implementing the formula

// long xor = (n % 4 == 0) ? n : (n % 4 == 1) ? 1 : (n % 4 == 2) ? n + 1 : 0;

//Faster way of implementing the formula

// long xor = (n>>1)&1 ^ (((n&1)>0)?1:n);

long xor = (n>>1)&1 ^ (((n&1)>0)?1:n);

for (long i = 0; i < n; i++)

{

xor = xor ^ a[i];

}

//Missing number

System.out.println(xor);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值