zoukankan      html  css  js  c++  java
  • 找出缺失整数

    题目:一个无序数组里有99个不重复正整数,范围从1到100,唯独缺少一个整数。如何找出这个缺失的整数?

    解法一: 

    创建一个HashMap,以1到100为键,值都是0 。然后遍历整个数组,每读到一个整数,就找到HashMap当中对应的键,让其值加一。

    由于数组中缺少一个整数,最终一定有99个键对应的值等于1, 剩下一个键对应的值等于0。遍历修改后的HashMap,找到这个值为0的键。

    假设数组长度是N,那么该解法的时间复杂度是O(1),空间复杂度是O(N)。

    解法二:

    先把数组元素进行排序,然后遍历数组,检查任意两个相邻元素数值是否是连续的。如果不连续,则中间缺少的整数就是所要寻找的;如果全都连续,则缺少的整数不是1就是100。

    假设数组长度是N,如果用时间复杂度为O(N*LogN)的排序算法进行排序,那么该解法的时间复杂度是O(N*LogN),空间复杂度是O(1)。

    解法三:

    很简单也很高效的方法,先算出1+2+3....+100的合,然后依次减去数组里的元素,最后得到的差,就是唯一缺失的整数。

    假设数组长度是N,那么该解法的时间复杂度是O(N),空间复杂度是O(1)。
      1 java代码如下
      2 
      3 import java.util.Arrays;
      4 import java.util.HashMap;
      5 import java.util.Random;
      6 //寻找缺失的整数
      7 //一个无序数组里有99个不重复正整数,范围从1到100,唯独缺少一个整数。如何找出这个缺失的整数
      8 public class LackData {
      9      public static void main(String args[])
     10      {
     11           //随机生成1-100的一个数作为缺失数
     12           Random rand =new Random();
     13           int miss=0;
     14           miss=rand.nextInt(100)+1;
     15           System.out.println("缺失的数为"+miss);
     16           //生成缺失了一个数之后的数组
     17           int[] missArray = new int[99];
     18           int j=0;
     19           for(int i=1;i<=100;i++)
     20           {
     21               if(i!=miss)
     22               {
     23                    missArray[j] = i;
     24                    j++;
     25               }
     26           }
     27           System.out.println("解法一:"+solution1(missArray));
     28           System.out.println("解法二:"+solution2(missArray));
     29           System.out.println("解法三:"+solution3(missArray));
     30      }
     31      /*解法一
     32       * 创建一个HashMap,以1到100为键,值都是0 。然后遍历整个数组,每读到一个整数,就找到HashMap当中对应的键,让其值加一。
     33       * 由于数组中缺少一个整数,最终一定有99个键对应的值等于1, 剩下一个键对应的值等于0。遍历修改后的HashMap,找到这个值为0的键。
     34       * 假设数组长度是N,那么该解法的时间复杂度是O(1),空间复杂度是O(N)。**/
     35      public static int solution1(int[] missArray)
     36      {
     37           int missnumber = 0;
     38           //初始化map
     39           HashMap<Integer, Integer> myMap = new HashMap<Integer, Integer>(); 
     40           for(int i=1;i<=100;i++)
     41           {
     42               myMap.put(i, 0);
     43           }
     44           //历整个数组,每读到一个整数,就找到HashMap当中对应的键,让其值加一
     45           for(int m:missArray)
     46           {
     47               myMap.put(m, myMap.get(m)+1);
     48           }
     49           //遍历修改后的HashMap,找到这个值为0的键
     50           for (int key : myMap.keySet()) {
     51               if(myMap.get(key)==0)
     52               {
     53                    missnumber = key;
     54                    break;
     55               }
     56            }
     57           return missnumber;
     58      }
     59      /*
     60       * 解法二:
     61       * 先把数组元素进行排序,然后遍历数组,检查任意两个相邻元素数值是否是连续的。如果不连续,则中间缺少的整数就是所要寻找的;如果全都连续,则缺少的整数不是1就是100。
     62       * 假设数组长度是N,如果用时间复杂度为O(N*LogN)的排序算法进行排序,那么该解法的时间复杂度是O(N*LogN),空间复杂度是O(1)。
     63       */
     64      public static int solution2(int[] missArray)
     65      {
     66           int missnumber = 0;
     67           //数组排序
     68           Arrays.sort(missArray);
     69           //检查是否相邻
     70           for(int i=0;i<missArray.length-1;i++)
     71           {
     72               if(missArray[i+1]-missArray[i]!=1)
     73               {
     74                    missnumber=missArray[i]+1;
     75               }
     76           }
     77           //如果检查到相邻则返回否则缺失的数为100
     78           if(missnumber!=0)
     79           {
     80               return missnumber;
     81           }
     82           else {
     83               return 100;
     84           }
     85      }
     86      /*
     87       * 解法三:
     88       * 很简单也很高效的方法,先算出1+2+3....+100的合,然后依次减去数组里的元素,最后得到的差,就是唯一缺失的整数。
     89       * 假设数组长度是N,那么该解法的时间复杂度是O(N),空间复杂度是O(1)。
     90       */
     91      public static int solution3(int[] missArray)
     92      {
     93           int missnumber=0;
     94           int all = 0;
     95           int missall = 0;
     96           for(int i=1;i<=100;i++)
     97           {
     98               all = all+i;
     99           }
    100           for(int m:missArray)
    101           {
    102               missall = missall+m;
    103           }
    104           return all-missall;
    105      }
    106 }
    题目扩展:一个无序数组里有若干个正整数,范围从1到100,其中99个整数都出现了偶数次,只有一个整数出现了奇数次(比如1,1,2,2,3,3,4,5,5),如何找到这个出现奇数次的整数?
    解法一:
    创建一个HashMap,以1到100为键,值都是0 。然后遍历整个数组,每读到一个整数,就找到HashMap当中对应的键,让其值加一。由于数组中缺少一个整数,最终一定有99个键对应的值为偶数, 剩下一个键对应的值为奇数。遍历修改后的HashMap,找到这个值为奇数 的键。假设数组长度是N,那么该解法的时间复杂度是O(1),空间复杂度是O(N)。
    解法二 遍历整个数组,依次做异或运算。由于异或在位运算时相同为0,不同为1,因此所有出现偶数次的整数都会相互抵消变成0,只有唯一出现奇数次的整数会被留下。假设数组长度是N,那么该解法的时间复杂度是O(N),空间复杂度是O(1)。
      1 import java.util.HashMap;
      2 import java.util.Random;
      3 import javax.xml.transform.Templates;
      4 //题目扩展:一个无序数组里有若干个正整数,范围从1到100,其中99个整数都出现了偶数次,只有一个整数出现了奇数次(比如1,1,2,2,3,3,4,5,5),如何找到这个出现奇数次的整数?
      5 public class LackDataExtension {
      6      public static void main(String args[])
      7      {
      8           //随机生成1-100的一个数作为出现基数次的数
      9           Random rand =new Random();
     10           int miss=0;
     11           miss=rand.nextInt(100)+1;
     12           System.out.println("缺失的数为"+miss);
     13           //存储每个数出现的次数 key为数value为该数出现的次数
     14            HashMap<Integer, Integer> store = new HashMap<Integer,Integer>();
     15            int number = 0;
     16            for(int i=1;i<=100;i++)
     17            {
     18                int temp = 0;
     19                if(i!=miss)
     20                {
     21                     temp = randEven();
     22                     store.put(i, temp);
     23                     number = number+temp;
     24                }
     25                else
     26                {
     27                     temp = randOdd();
     28                     store.put(i, temp);
     29                     number = number+temp;
     30               }
     31            }
     32           //生成缺99个整数都出现了偶数次,只有一个整数出现了奇数次的数组
     33           int[] missArray = new int[number];
     34           int temp=0;
     35           for(int i=1;i<=100;i++)
     36           {    
     37               for(int j=0;j<store.get(i);j++)
     38               {
     39                    missArray[temp] = i;
     40                    temp++;
     41               }
     42           }
     43           System.out.println("解法一:"+solution1(missArray));
     44           System.out.println("解法二:"+solution2(missArray));
     45      }
     46      /*
     47       * 解法1
     48       * 创建一个HashMap,以1到100为键,值都是0 。然后遍历整个数组,每读到一个整数,就找到HashMap当中对应的键,让其值加一。
     49       * 由于数组中缺少一个整数,最终一定有99个键对应的值为偶数, 剩下一个键对应的值为奇数。遍历修改后的HashMap,找到这个值为奇数的键。
     50       * 假设数组长度是N,那么该解法的时间复杂度是O(1),空间复杂度是O(N)。**/
     51      public static int solution1(int[] missArray)
     52      {
     53           int missnumber = 0;
     54           //初始化map
     55           HashMap<Integer, Integer> myMap = new HashMap<Integer, Integer>(); 
     56           for(int i=1;i<=100;i++)
     57           {
     58               myMap.put(i, 0);
     59           }
     60           //历整个数组,每读到一个整数,就找到HashMap当中对应的键,让其值加一
     61           for(int m:missArray)
     62           {
     63               myMap.put(m, myMap.get(m)+1);
     64           }
     65           //遍历修改后的HashMap,找到这个值为0的键
     66           for (int key : myMap.keySet()) {
     67               if(myMap.get(key)%2==1)
     68               {
     69                    missnumber = key;
     70                    break;
     71               }
     72            }
     73           return missnumber;
     74      }
     75      /*
     76       * 解法2
     77       * 遍历整个数组,依次做异或运算。由于异或在位运算时相同为0,不同为1,因此所有出现偶数次的整数都会相互抵消变成0,只有唯一出现奇数次的整数会被留下。
     78       * 假设数组长度是N,那么该解法的时间复杂度是O(N),空间复杂度是O(1)。**/
     79      public static int solution2(int[] missArray)
     80      {
     81           int missnumber = 0;
     82           for(int m:missArray)
     83           {
     84               missnumber = missnumber^m;
     85           }
     86           return missnumber;
     87      }
     88      //生成1-10的奇数
     89      public static int randOdd()
     90      {
     91           Random rand =new Random();
     92           int temp = rand.nextInt(5)+1;
     93           return temp*2-1;
     94      }
     95      //生成1-10的偶数
     96      public static int randEven()
     97      {
     98           Random rand =new Random();
     99           int temp = rand.nextInt(5)+1;
    100           return temp*2;
    101      }
    102 }
    题目第二次扩展:一个无序数组里有若干个正整数,范围从1到100,其中98个整数都出现了偶数次,只有两个整数出现了奇数次(比如1,1,2,2,3,4,5,5),如何找到这个出现奇数次的整数?
     
    解法:

    遍历整个数组,依次做异或运算。由于数组存在两个出现奇数次的整数,所以最终异或的结果,等同于这两个整数的异或结果。这个结果中,至少会有一个二进制位是1(如果都是0,说明两个数相等,和题目不符)。

    举个例子,如果最终异或的结果是5,转换成二进制是00000101。此时我们可以选择任意一个是1的二进制位来分析,比如末位。把两个奇数次出现的整数命名为A和B,如果末位是1,说明A和B转为二进制的末位不同,必定其中一个整数的末位是1,另一个整数的末位是0。

    根据这个结论,我们可以把原数组按照二进制的末位不同,分成两部分,一部分的末位是1,一部分的末位是0。由于A和B的末位不同,所以A在其中一部分,B在其中一部分,绝不会出现A和B在同一部分,另一部分没有的情况。

    这样一来就简单了,我们的问题又回归到了上一题的情况,按照原先的异或解法,从每一部分中找出唯一的奇数次整数即可。

    假设数组长度是N,那么该解法的时间复杂度是O(N)。把数组分成两部分,并不需要借助额外存储空间,完全可以在按二进制位分组的同时来做异或运算,所以空间复杂度仍然是O(1)。
      1 import java.util.HashMap;
      2 import java.util.Random;
      3 import javax.xml.transform.Templates;
      4 //题目扩展:一个无序数组里有若干个正整数,范围从1到100,其中98个整数都出现了偶数次,只有两个整数出现了奇数次(比如1,1,2,2,3,4,5,5),如何找到这个出现奇数次的整数?
      5 public class LackDataExtensionTwo {
      6      public static void main(String args[])
      7      {
      8           //随机生成1-100的两个数作为出现奇数次的数
      9           Random rand =new Random();
     10           int miss=0;
     11           miss=rand.nextInt(100)+1;
     12           System.out.println("奇数次的数1为"+miss);
     13           int miss1=0;
     14           do
     15           {
     16               miss1=rand.nextInt(100)+1;
     17           }
     18           while(miss1!=0&&miss1==miss);
     19           System.out.println("奇数次的数2为"+miss1);
     20           //存储每个数出现的次数 key为数value为该数出现的次数
     21            HashMap<Integer, Integer> store = new HashMap<Integer,Integer>();
     22            int number = 0;
     23            for(int i=1;i<=100;i++)
     24            {
     25                int temp = 0;
     26                if(i!=miss&&i!=miss1)
     27                {
     28                     temp = randEven();
     29                     store.put(i, temp);
     30                     number = number+temp;
     31                }
     32                else
     33                {
     34                     temp = randOdd();
     35                     store.put(i, temp);
     36                     number = number+temp;
     37               }
     38            }
     39           //生成缺98个整数都出现了偶数次,只有二个整数出现了奇数次的数组
     40           int[] missArray = new int[number];
     41           int temp=0;
     42           for(int i=1;i<=100;i++)
     43           {    
     44               for(int j=0;j<store.get(i);j++)
     45               {
     46                    missArray[temp] = i;
     47                    temp++;
     48               }
     49           }
     50           System.out.print("解法一:");
     51           solution1(missArray);
     52           System.out.print("解法二:");
     53           solution2(missArray);
     54      }
     55      /*
     56       * 解法1
     57       * 创建一个HashMap,以1到100为键,值都是0 。然后遍历整个数组,每读到一个整数,就找到HashMap当中对应的键,让其值加一。
     58       * 由于数组中缺少一个整数,最终一定有98个键对应的值为偶数, 剩下二个键对应的值为奇数。遍历修改后的HashMap,找到这个值为奇数的键。
     59       * 假设数组长度是N,那么该解法的时间复杂度是O(1),空间复杂度是O(N)。**/
     60      public static void solution1(int[] missArray)
     61      {
     62           int missnumber = 0;
     63           //初始化map
     64           HashMap<Integer, Integer> myMap = new HashMap<Integer, Integer>(); 
     65           for(int i=1;i<=100;i++)
     66           {
     67               myMap.put(i, 0);
     68           }
     69           //历整个数组,每读到一个整数,就找到HashMap当中对应的键,让其值加一
     70           for(int m:missArray)
     71           {
     72               myMap.put(m, myMap.get(m)+1);
     73           }
     74           //遍历修改后的HashMap,找到这个值为0的键
     75           for (int key : myMap.keySet()) {
     76               if(myMap.get(key)%2==1)
     77               {
     78                    missnumber = key;
     79                    System.out.println("奇数的数为"+missnumber);
     80               }
     81            }
     82      }
     83      /*
     84       * 解法2
     85       * 遍历整个数组,依次做异或运算。由于数组存在两个出现奇数次的整数,所以最终异或的结果,等同于这两个整数的异或结果。这个结果中,至少会有一个二进制位是1(如果都是0,说明两个数相等,和题目不符)。
     86       * 举个例子,如果最终异或的结果是5,转换成二进制是00000101。此时我们可以选择任意一个是1的二进制位来分析,比如末位。
     87       * 把两个奇数次出现的整数命名为A和B,如果末位是1,说明A和B转为二进制的末位不同,必定其中一个整数的末位是1,另一个整数的末位是0。
     88       * 根据这个结论,我们可以把原数组按照二进制的末位不同,分成两部分,一部分的末位是1,一部分的末位是0。
     89       * 由于A和B的末位不同,所以A在其中一部分,B在其中一部分,绝不会出现A和B在同一部分,另一部分没有的情况。
     90       * 这样一来就简单了,按照原先的异或解法,从每一部分中找出唯一的奇数次整数即可。
     91       * 假设数组长度是N,那么该解法的时间复杂度是O(N)。把数组分成两部分,并不需要借助额外存储空间,完全可以在按二进制位分组的同时来做异或运算,所以空间复杂度仍然是O(1)。
     92 **/
     93      public static void solution2(int[] missArray)
     94      {
     95           int temp = 0;
     96           //数组所有元素异或
     97           for(int m:missArray)
     98           {
     99               temp = temp^m;
    100           }
    101           int site=1;
    102           //找到1位为1的元素
    103           while((temp & (1 << site))==0)
    104           {
    105               site++;
    106           }
    107           int num1 = 0;
    108           int num2 = 0;
    109           for(int m:missArray)
    110           {
    111               if(getBit(m, site))
    112               {
    113                    num1 = num1^m;
    114               }
    115               else {
    116                    num2 = num2^m;
    117               }
    118           }
    119           System.out.println("奇数的数为"+num1);
    120           System.out.println("奇数的数为"+num2);
    121      }
    122      //生成1-10的奇数
    123      public static int randOdd()
    124      {
    125           Random rand =new Random();
    126           int temp = rand.nextInt(5)+1;
    127           return temp*2-1;
    128      }
    129      //生成1-10的偶数
    130      public static int randEven()
    131      {
    132           Random rand =new Random();
    133           int temp = rand.nextInt(5)+1;
    134           return temp*2;
    135      }
    136      //获取 整数 num 的第 i 位的值
    137     private static boolean getBit(int num, int i)
    138     {
    139         return ((num & (1 << i)) != 0);//true 表示第i位为1,否则为0
    140     }
    141 }
  • 相关阅读:
    【Phalapi】新加Namespace (模块)
    【PHP】 curl 上传文件 流
    牛掰!我是这么把个人博客粉丝转到公众号的
    Stack Overflow 上 250W 浏览量的一个问题:你对象丢了
    为什么人到中年就危机了呢?
    Java 并发编程(三):如何保证共享变量的可见性?
    如果有人问你 JFinal 如何集成 EhCache,把这篇文章甩给他
    国庆佳节第四天,谈谈我月收入增加 4K 的故事
    为什么要将局部变量的作用域最小化?
    面试官:兄弟,说说基本类型和包装类型的区别吧
  • 原文地址:https://www.cnblogs.com/icysnow/p/8057718.html
Copyright © 2011-2022 走看看