使用“初中知识”实现查找重复最优算法 + 最终极限算法

这是园子里讨论了好长时间的题目了:
1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?
发起文章: 算法题,求高手. 作者: 莫贝特(MBetter) 
算法改进: 利用异或的特性解决,找出重复数的问题,应该是目前最优算法。  作者: Ivony...

莫贝特给出的算法是: 将所有数加起来,减去1+2+...+1000的和
Ivony给出的算法是:  将所有的数全部异或,得到的结果与1^2^3^...^1000的结果进行异或,得到的结果就是重复数
两位算法的时间复杂度都是: 2n (莫贝特的算法可以用高斯算法简化)

我把题目扩展了一下,将1000换成n,让些题更通用一些:
1-n放在含有n+1个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?(n可能为奇数)(注意:数组是无序的,有序数组很好解决不讨论)

下面是我的算法,先给出代码,c#语言

ExpandedBlockStart.gif ContractedBlock.gif          /**/ /// <summary>
        
/// 查找重复的数
        
/// </summary>
        
/// <param name="ints">1..n无序序列加上1..n之间的一个数</param>
        
/// <returns>重复的数</returns>

         public   static   int  GetRepeated( int [] array)
ExpandedBlockStart.gifContractedBlock.gif        
{
            
int temp = 0;
            
foreach (int i in array)
                
if (i % 2 == 1) temp += i + 1;
                
else temp -= i;
            
if (array.Length % 2 == 0) temp -= array.Length;//n为奇数要处理一下
            return temp < 0 ? -temp : temp - 1;
        }
原理如下(n为偶数时):
(1-2)+(3-4)+(5-6)+(7-8)+....+(n-1 - n)  等于多少?先不管,再改进一下
((1+1)-2)+((3+1)-4)+((4+1)-5)+((5+1)-6)+...+((n-1+1) - n) 等于多少? 零!这个公式证明初中生都会!

这是有序序列,对无序的情况我们可以这样理解: 从数组中依次读数,如果读到是奇数则加上再加1,如果偶数则减去。
和代码中的foreach对照一下吧,应该比较好理解!
函数中 倒数第二行对n是奇数的情况作了些处理。

最后返回处理:
      如果重复的数是偶数,则肯定被减了,则返回它的负值-temp;
      如果重复的数是奇数,则肯定被加了,而且还多加了1, 返回 temp-1。

这个算法时间复杂度是n,空间复杂度是1,代码行数是6,原理也简单。

利用初中(小学奥赛估计也会)的知识解决一个算法问题,感觉算不上高手。只能感叹我们以前的知识忘记了太多了!

----------------------------------------------------------------------------------------------------------
刚才又看前面两篇帖子的回复,发现了loogn 提供的一个算法,本人修正了一下:
         public   static   int  GetRepeated2( int [] array)
ExpandedBlockStart.gifContractedBlock.gif        
{
            
int temp = 0;
            
for (int i = 0; i < array.Length; i++)
                temp 
+= array[i] - i ;
            
return temp;
        }
算法原理: 改进莫贝特的算法,加减加减加减...,而不是(加加加...)减(加加加...)。出现溢出的可能性也小了很多!
更是精简,强人!!

不甘落后,我用lambda再改进一下:
         public   static   int  GetRepeated3( int [] array)
        {
            
return  array.Select((i, j)  =>  i  -  j ).Sum() ;
        }
简单说明一下:
      方法三中的“i”相当与方法二中的“array[i]”;
      方法三中的“j”相当于方法二中的“i”

其它大可不必写成一个函数,像下面这样直接调用就好了,也算是最后的 极限算法了。
     int  repeatedNum  =  array.Select((i, j)  =>  i  -  j ).Sum() ;
array就是包含n+1个数的数组,repeatedNum就是其中唯一重复的数。 这应该是极限了吧!

大家可以调试运行一下这几种方法都可以通过,有问题拍我。

本人系列文章《 c#扩展方法奇思妙用》,敬请关注!

转载于:https://www.cnblogs.com/ldp615/archive/2009/08/08/1541825.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值