【Java】 劍指offer(2) 不修改數組找出重複的數字

 

本文參考自《劍指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

完整Java代碼

(含測試代碼)指針

/**
 * 
 * @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
FindDuplication2

 

複雜度

時間複雜度說明:函數countRange()將被調用O(logn)次,每次須要O(n)的時間。

時間複雜度:O(nlogn)  (while循環爲O(logn),coutRange()函數爲O(n))

空間複雜度:O(1)

 

 更多:《劍指Offer》Java實現合集

相關文章
相關標籤/搜索