zoukankan      html  css  js  c++  java
  • 面试题3:数组中重复的数字

    数据结构中围绕数组、字符串、链表、树、栈以及队列,会有大量的面试题。

    此题是关于数组的问题,另外,根据不同的具体要求,此题有多种考法,具体代码实现也会不同。

    牛客网上的题目 :

    在一个长度为n的数组里的所有数字都在0到n-1的范围内。 
    数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。
    请找出数组中任意一个重复的数字。
     例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。 

    《剑指offer》上根据不同的具体要求,出了两个题目,其中第一个题目与牛客网上的相同。如下:

    在一个长度为n的数组里的所有数字都在0到n-1的范围内。
     数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 
    例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。 

    简单理解就是判断某个长度为n的数组中,是否有重复的数字。
    根据牛客网上的提示代码:

     public boolean duplicate(int numbers[],int length,int [] duplication)

    是要求 判断值返回,并把第一个重复的数字放到duplication[0]中。

    我个人的做法是:

     1 public static boolean duplicate(int numbers[],int length,int [] duplication) {
     2         if(numbers==null||numbers.length==0){
     3             duplication[0] = -1; 
     4             return false;
     5         }
     6         ArrayList<Integer> arr = new ArrayList<Integer>();
     7         //Arrays.sort(numbers);
     8         //System.out.println(Arrays.toString(numbers));
     9         for(int i:numbers){
    10             arr.add(i);
    11         }
    12         //Iterator<Integer> it = arr.iterator();
    13         /*while(it.hasNext()){
    14             System.out.print(it.next()+" ");
    15         }*/
    16         for(int i:numbers){
    17             if(arr.contains(i)){
    18                 
    19                 //it.remove();
    20                 int j = arr.indexOf(i);
    21                 arr.remove(j);//根据下标 去除对应的下标
    22                 //System.out.println(arr);
    23                 if(arr.contains(i)){
    24                     duplication[0]=i;
    25                     System.out.println(i);
    26                     return true;
    27                 }
    28             }
    29         }
    30         return false;
    31     }

    主要思路是:①先判断是否输入的数组,是否为空或者长度为0,如果是,直接返回false。如果不是,继续执行。

    ②定义一个ArrayList arr,用一个for循环将numbers中的值,add(i)到arr中。

    ③再for循环numbers数组,用arr.contains(i)判断是否包含对应的数字,如果包含,删除对应数字,再进行arr.contains(i),如果还包含,就说明此数字重复,返回true即可。

    虽然结果是对的,但是由于另外创建了ArrayList,导致空间复杂度为O(n)。

    根据《剑指offer》上提出的思路,实现下面代码,使得空间复杂度为O(1):

     1 /*
     2      * 交换数组内的数字顺序
     3      */
     4     public static boolean duplicate2(int numbers[],int length,int [] duplication) {
     5         if(numbers==null||numbers.length==0){
     6             duplication[0] = -1; 
     7             return false;
     8         }
     9         for(int i = 0;i<length;i++){
    10             while(numbers[i]!=i)
    11             {
    12                 if(numbers[i]==numbers[numbers[i]]){
    13                     duplication[0] = numbers[i];
    14                     System.out.println(duplication[0]);
    15                     return true;
    16                 }
    17                 int temp = numbers[i];
    18                 numbers[i] = numbers[temp];
    19                 numbers[temp] = temp;
    20             }
    21         }
    22         return false;
    23     }

    主要思路是:①先判断输入的数组是否为空,或者数组长度为0。

    ②让数组内的数字和数组的下标之间产生关联,即如果数组内的数字与当前数字的数组下标不相等,就将数组内的数字,交换到对应数字下标的位置,例如数组内numbers[0]的值是2,2不等于0,则将2与numbers[2]的交换。

    ③在数组内的数字与当前数字的数组下标不相等的情况下,如果出现,当前数字与即将交换位置的数字相等,则说明当前数字重复,返回true。例如,如果numbers[0]为2,2不等于0,则判断2是否等于numbers[2],如果numbers[2]为2,则说明2是重复的,结束。

    另外,如果将题目改一下,限制一下数组里数字的范围,就是《剑指offer》上这道题的第二个题目:

    在一个长度为n+1的数组里的所有数字都在1到n的范围内。 
    数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。
    请找出数组中任意一个重复的数字。 例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2or3。

    根据书上给出的思路,自己实现的代码:

     1 public static boolean duplicate3(int[] numbers, int length, int[] duplication) {
     2         if(numbers==null||numbers.length==0){
     3             duplication[0] = -1; 
     4             return false;
     5         }
     6         //int start = 1,end = length-1;
     7         int start = 1,end = length-1;
     8         while(end >= start){
     9             //int middle = ((end-start)>>1)+start;
    10             int middle = (end-start)/2 + start;
    11             int count = countRange(numbers,length,start,middle);
    12             if(start==end){
    13                 if(count>1){
    14                     duplication[0] = start;
    15                     System.out.println(start);
    16                     return true;
    17                 }else{
    18                     duplication[0] = -1; 
    19                     System.out.println(start);
    20                     return false;
    21                 }
    22             }
    23             
    24             if(count>middle){
    25                 end = middle;
    26             }else{
    27                 start = middle+1;
    28             }
    29         }
    30         return false;
    31     }
    32     public static int countRange(int[] numbers, int length, int start, int end) {
    33         int count=0;
    34         for(int i=0;i<length;i++){
    35             if(numbers[i]>=start && numbers[i]<=end){
    36                 count++;
    37             }
    38         }
    39         return count;
    40         
    41     }

    用的是类似于二分法的思路,例如在1-3的范围中,如果小于3和大于1的数字的个数count,大于3,说明这个范围的数字是有重复的,然后进一步缩小范围,然后再进行计数,直到start==end的
    范围中,出现count>1的,即是重复的数。

    这种算法也是有缺陷的,比如在1-2范围内,有两个2,此时不能确定是每个数字各出现一次,还是某个数字出现两次。

  • 相关阅读:
    Python3 tkinter基础 Radiobutton variable 默认选中的按钮
    oracle函数NVL,NVL2和NULLIF之间的区别和使用
    js如何返回两个数的商的整数和余数部分?
    解决win10打开组策略弹出管理模板对话框问题
    asp.net mvc中动作方法的重定向
    asp.net mvc如何获取url的相关信息
    vs2015如何使用附加进程调试发布在IIS上项目
    未能加载文件或程序集“Oracle.DataAccess”或它的某一个 依赖项。如何解决?
    C#中使用SqlBulkCopy的批量插入和OracleBulkCopy的批量插入
    oracle中计算两个日期的相差天数、月数、年数、小时数、分钟数、秒数等
  • 原文地址:https://www.cnblogs.com/weiziqiang/p/8822162.html
Copyright © 2011-2022 走看看