zoukankan      html  css  js  c++  java
  • 使用“初中知识”实现查找重复最优算法 + 最终极限算法

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

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

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

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

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

            public static int GetRepeated(int[] array)
            
    {
                
    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)
            
    {
                
    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#扩展方法奇思妙用》,敬请关注!
  • 相关阅读:
    flutter 和 NTFS
    APIO2020 游记
    CF1336F Journey
    ZJOI2020 游记
    CF568E Longest Increasing Subsequence
    CSP2020 游记
    洛谷 P6217 简单数论题
    CF587F Duff is Mad
    CF526G Spiders Evil Plan
    WC2021 游记
  • 原文地址:https://www.cnblogs.com/ldp615/p/1541825.html
Copyright © 2011-2022 走看看