剑指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版)的主要内容,如果未能解决你的问题,请参考以下文章