本文參考自《劍指offer》一書,代碼採用Java語言。html
更多:《劍指Offer》Java實現合集java
在一個長度爲n+1的數組裏的全部數字都在1到n的範圍內,因此數組中至少有一個數字是重複的。請找出數組中任意一個重複的數字,但不能修改輸入的數組。例如,若是輸入長度爲8的數組{2, 3, 5, 4, 3, 2, 6, 7},那麼對應的輸出是重複的數字2或者3。數組
數組長度爲n+1,而數字只從1到n,說明一定有重複數字。能夠由二分查找法拓展:把1~n的數字從中間數字m分紅兩部分,若前一半1~m的數字數目超過m個,說明重複數字在前一半區間,不然,在後半區間m+1~n。每次在區間中都一分爲二,知道找到重複數字。ide
更簡單的思路:把該數組看做一個鏈表,下標表明當前結點,值表明next指針,具體參考Find the Duplicate Number,時間複雜度僅爲O(n)函數
測試用例post
1.數組中帶一個或多個重複數字測試
2.數組中不包含重複的數字url
3.無效輸入測試用例(空數組,數組數字越界等)spa
(含測試代碼)指針
/** * * @Description 不修改數組找出重複的數字 * * @author yongh * @date 2018年7月16日 上午11:47:44 */ /* * 題目:在一個長度爲n+1的數組裏的全部數字都在1到n的範圍內,因此數組中至 * 少有一個數字是重複的。請找出數組中任意一個重複的數字,但不能修改輸入的 * 數組。例如,若是輸入長度爲8的數組{2, 3, 5, 4, 3, 2, 6, 7},那麼對應的 * 輸出是重複的數字2或者3。 */ public class FindDuplication2 { /** * 找到數組中一個重複的數字 * 返回-1表明無重複數字或者輸入無效 */ public int getDuplicate(int[] arr) { if (arr == null || arr.length <= 0) { System.out.println("數組輸入無效!"); return -1; } for (int a : arr) { if (a < 1 || a > arr.length - 1) { System.out.println("數字大小超出範圍!"); return -1; } } int low = 1; int high = arr.length - 1; // high即爲題目的n int mid, count; while (low <= high) { mid = ((high - low) >> 2) + low; count = countRange(arr, low, mid); if (low == high) { if (count > 1) return low; else break; // 必有重複,應該不會出現這種狀況吧? } if (count > mid - low + 1) { high = mid; } else { low = mid + 1; } } return -1; } /** * 返回在[low,high]範圍中數字的個數 */ public int countRange(int[] arr, int low, int high) { if (arr == null) return 0; int count = 0; for (int a : arr) { if (a >= low && a <= high) count++; } return count; } // ==================================測試代碼================================== /** *數組爲null */ public void test1() { System.out.print("test1:"); int[] a = null; int dup = getDuplicate(a); if (dup >= 0) System.out.println("重複數字爲:" + dup); } /** *數組數字越界 */ public void test2() { System.out.print("test2:"); int[] a = { 1, 2, 3, 4 }; int dup = getDuplicate(a); if (dup >= 0) System.out.println("重複數字爲:" + dup); } /** *數組帶重複數字 */ public void test3() { System.out.print("test3:"); int[] a = { 1, 2, 3, 2, 4 }; int dup = getDuplicate(a); if (dup >= 0) System.out.println("重複數字爲:" + dup); } public static void main(String[] args) { FindDuplication2 f2 = new FindDuplication2(); f2.test1(); f2.test2(); f2.test3(); } }
test1:數組輸入無效!
test2:數字大小超出範圍!
test3:重複數字爲:2
時間複雜度說明:函數countRange()將被調用O(logn)次,每次須要O(n)的時間。
時間複雜度:O(nlogn) (while循環爲O(logn),coutRange()函數爲O(n))
空間複雜度:O(1)