剑指offer——面试题3:数组中重复的数字(Java版)

Posted roy-chencainiao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer——面试题3:数组中重复的数字(Java版)相关的知识,希望对你有一定的参考价值。

题目一:找出数组中任意重复的数字

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

思路:

      看到这道题后我的第一个想法是使用hash表对数组按顺序从头到尾进行扫描,扫描到不包含的数字就将其加入hash表中,扫描到hash表中包含的数字则代表该数字为重复的数字,则返回该重复的数字。这个算法的时间复杂度是O(n),但是它提高时间效率的代价是必须要有一个大小为O(n)的hash表。在面试中,面试官除了会考察程序员是否能解决一个问题,还会关注他是否能考虑周全,比如使用尽量低的时间复杂度和空间复杂度的算法

      第二个方法是对数组进行排序,然后对数组进行相邻两个数字的对比,找出相同的数字。排序一个长度为n的数组需要O(nlogn)的时间。这个方法的时间复杂度也比较高,再看看还有没有更优解。

      重复查看题目,注意到所有数字都在0到n-1的范围,这样的话如果该数组不包含重复的数字,那么在排完序后数字i应出现在下角标为i的位置。那么可以这样排序,对数组从头到尾扫描,扫描到n[i]时,判断n[i]是否等于i,是的话代表它在正确的位置,扫描下一个,不是的话先判断下角标为n[i]的数字是否等于i,是的话那么我们就找到这个重复的数字了,返回该数字退出循环即可,不是的话就将n[i]中的数字与下角标为n[i]的数字交换。一直循环直到扫描完整个数组。若循环完整个数组后仍然没有返回值,则代表该数组没有重复的数字。

注:在编写解决问题的函数之前先写单元测试用例,这是一种很好的习惯,在面试中会给面试官带来很好的印象。

关键代码实现:

 1     private static int checkDuplicate(int[] ar) {
 2         int duplicate;
 3 
 4         if (ar == null) {// 避免数组为空的情况
 5             return -2;
 6         }
 7 
 8         for (int i = 0; i < ar.length; i++) {// 避免出现数组内容格式错误
 9             if (ar[i] < 0 || ar[i] > ar.length - 1) {
10                 return -3;
11             }
12         }
13 
14         for (int i = 0; i < ar.length; i++) {
15             while (ar[i] != i) {
16                 if (ar[i] == ar[ar[i]]) {
17                     duplicate = ar[i];
18                     System.out.println(
19                             "The array contains duplicate numbers." 
20                     + "One of the duplicate number is: " + duplicate);
21                     return duplicate;
22                 }
23                 swap(ar, i, ar[i]);
24             }
25         }
26         return -1;
27     }
28   //对数组中下角标为c和d的数字交换
29     private static void swap(int[] ar, int c, int d) {
30         int temp = ar[c];
31         ar[c] = ar[d];
32         ar[d] = temp;
33     }

 

 下面对代码进行测试

测试用例及完整代码:

 1 public class Duplication3 {
 2     public static void main(String[] args) {
 3         int[] a = { 3, 4, 1, 0, 2, 5, 6};// 数组中不包含重复数字
 4         int[] b = { 3, 4, 1, 0, 2, 5, 3};// 数组中含有一个重复数字
 5         int[] c = { 4, 6, 1, 0, 2, 5, 0};//数组中重复数字为最小值
 6         int[] d = { 4, 6, 1, 0, 2, 6, 5};//数组中重复数字为最大值
 7         int[] e = { 2, 3, 1, 0, 2, 5, 3 };// 数组中含有多个重复数字
 8         int[] f = { 2, 3, 1, 0, -1, 5, 3};// 数组中的数字格式错误
 9         int[] g = { 2, 3, 1, 0, 8, 5, 3};//数组中含有数字大于数组长度-1
10         int[] h = null;
11         
12         test("test1",a);
13         test("test2", b);
14         test("test3", c);
15         test("test4", d);
16         test("test5", e);
17         test("test6", f);
18         test("test7", g);
19         test("test8", h);
20     }
21 
22     private static void test(String s, int[] ar) {
23         System.out.println(s + ":");
24         int k = checkDuplicate(ar);
25         if (k < 0) {
26             switch (k) {
27             case -1:
28                 System.out.println("No duplicate numbers in this array!");
29                 break;
30             case -2:
31                 System.out.println("This array is null!");
32                 break;
33             case -3:
34                 System.out.println("This array content is malformed!");
35             }
36         }
37     }
38 
39     private static int checkDuplicate(int[] ar) {
40         int duplicate;
41 
42         if (ar == null) {// 避免数组为空的情况
43             return -2;
44         }
45 
46         for (int i = 0; i < ar.length; i++) {// 避免出现数组内容格式错误
47             if (ar[i] < 0 || ar[i] > ar.length - 1) {
48                 return -3;
49             }
50         }
51 
52         for (int i = 0; i < ar.length; i++) {
53             while (ar[i] != i) {
54                 if (ar[i] == ar[ar[i]]) {
55                     duplicate = ar[i];
56                     System.out.println(
57                             "The array contains duplicate numbers." 
58                     + "One of the duplicate number is: " + duplicate);
59                     return duplicate;
60                 }
61                 swap(ar, i, ar[i]);
62             }
63         }
64         return -1;
65     }
66 
67     private static void swap(int[] ar, int c, int d) {
68         int temp = ar[c];
69         ar[c] = ar[d];
70         ar[d] = temp;
71     }
72 }

 

以上是关于剑指offer——面试题3:数组中重复的数字(Java版)的主要内容,如果未能解决你的问题,请参考以下文章

8.剑指Offer --- 英文版新增面试题

[ 剑指offer ] 面试题对应的LeetCode

《剑指offer》第三_二题

面试题8:旋转数组的最小数字(剑指offer)

剑指offer之数组

剑指Offer-3~9题