1. 程式人生 > >【題3陣列中重複的數字】

【題3陣列中重複的數字】

【題3陣列中重複的數字】
【題目1】
在一個長度為n的數組裡的所有數字都在0-n-1的範圍內,陣列中某些數字是重複的,但不知道每個數字重複了幾次,請找出陣列中任意一個重複的數字,例如,如果輸入長度為7的陣列,{2,3,1,0,2,5,3},那麼對應的輸出是2或者3
【方法】
1.
(1)先把輸入陣列排序
(2)從頭到尾掃描排序後的陣列
(3)排一個長度為n的陣列需要O(nlogn)
2雜湊表
(1) 從頭到尾按順序掃描陣列的每個數字
(2) 每掃描一個用O(1)時間判斷雜湊表裡是否已經包含該數字
(3) 若包含則一個重複數字,若不包含則插入到雜湊表
3數字都在0~n-1範圍內排序之後,i將對應下標i的位置
重排陣列
(1)掃描到下標i的數字時,比較這個數字(m)是否=i
(2)若等於,掃描下一個。不等則與第m個數字比較
(3)如果與第m個數字相等,則 有一個重複數字
(4)把第i個數字與第m個數字交換,把m放到屬於他的位置
在這裡插入圖片描述


實現

package ti3;
/**
*
* 題目:在一個長度為n的數組裡的所有數字都在0到n-1的範圍內。陣列中某些數字是重複的,但不知道有幾個數字重複了,
* 也不知道每個數字重複了幾次。請找出陣列中任意一個重複的數字。例如,如果輸入長度為7的陣列{2, 3, 1, 0, 2, 5, 3},
* 那麼對應的輸出是重複的數字2或者3。
* test1:陣列輸入無效!
test2:陣列中無重複數字!
test3:數字大小超出範圍!
test4:重複數字為:2
*/
public class FindDuplication {
	/**
	 * 找到陣列中一個重複的數字
	 * 返回-1代表無重複數字或者輸入無效
	 */
	public int getDuplicate(int[] arr){
		if(arr == null || arr.length <= 0){
			System.out.println("陣列輸入無效");
			return -1;
		}
		for(int a:arr){
			if(a < 0 || a > arr.length - 1){
				System.out.println("數字大小超出範圍");
				return -1;
			}
		}
		for(int i = 0;i < arr.length;i++){
			int temp;
			while(arr[i] != i){
				if(arr[arr[i]] == arr[i]){
					return arr[i];
				}
				//交換arr[arr[i]]和arr[i]
				temp = arr[i];
				arr[i] = arr[temp];
				arr[temp] = temp;
			}
		}
		System.out.println("陣列中無重複的數字");
		return -1;
	}
	//測試程式碼
	//陣列為null
	public  void test1()
	{
		System.out.println("test1");
		int[] a = null;
		int  dup = getDuplicate(a);
		if(dup >= 0){
			System.out.println("重複數字為"+dup);
		}
	}
	//陣列無重複數字
	public  void test2()
	{
		System.out.println("test2");
		int[] a = {0,1,2,3};
		int  dup = getDuplicate(a);
		if(dup >= 0){
			System.out.println("重複數字為"+dup);
		}
	}
	//陣列數字越界
	public  void test3()
	{
		System.out.println("test3");
		int[] a = {1,2,3,4};
		int  dup = getDuplicate(a);
		if(dup >= 0){
			System.out.println("重複數字為"+dup);
		}
	}
	//重複數字為2
	public  void test4()
	{
		System.out.println("test4");
		int[] a = {1,2,3,2,4};
		int  dup = getDuplicate(a);
		if(dup >= 0){
			System.out.println("重複數字為"+dup);
		}
	}
	public static void main(String[] args) {
		FindDuplication f = new FindDuplication();
		f.test1();
		f.test2();
		f.test3();
		f.test4();
	}
}

【題目2不修改陣列找出重複的數字】
在一個長度尾n+1的數組裡的所有數字都在1~n的範圍內,所有陣列中至少有一個數字時重複的。請找出陣列中任意一個重複的數字,但不能修改輸入的陣列。例如,輸入長度為8的陣列{2,3,5,4,3,2,6},那麼對應 的輸出是重複的數字2或3
注意:不能修改原陣列
方法:
1.
(1)建立一個長度為n+1的輔助陣列,逐一把原陣列的每個數字複製到輔助陣列
(2)若原陣列中被複制的數字為m,則複製到輔助陣列下標為m的位置
2.
(1)把從1~n數字從 中間的數字m分為2部分,1-m,m+1~n
(2)如果1~m數字的數目超過了m則這個一半包含重複的數字
否則,另一半m+1~n區間裡一定包含重複的數字
(3)繼續一分為二
在這裡插入圖片描述

實現

package ti3;

public class DuplicationInArrayNotEdit {
	private int countRange(int[] array,int length,int start,int end){
		if(start < 0 ||end > length-1)throw new IllegalArgumentException("Wrong Arguments");
		int count = 0;
		for(int i = 0;i<length;++i){
			if(array[i]<=end && array[i]>= start)++count;
		}
		return count;
	}
	public int returnOneDuplication(int[] array){
		if(array == null) throw new IllegalArgumentException("Wrong Arguments");
		int length = array.length;
		int start = 1;
		int end = length - 1;
		while(start <= end){
			int middle = ((end-start)>>1)+start;
			int count = countRange(array,length,start,middle);
			if(start == end){
				if(count >1)return start;
				else break;
			}
			if(count>middle - start+1)end = middle;
			else start = middle +1;//注意這個+1
		}
		return -1;
	}
	public static void main(String[] args) {
		DuplicationInArrayNotEdit duplicationInArrayNotEdit = new DuplicationInArrayNotEdit();
		int[] Array = new int[] {2,3,5,4,3,2,6,7};
		System.out.println(duplicationInArrayNotEdit.returnOneDuplication(Array));
	}
}

參考:
1.《劍指offer》
2.https://www.cnblogs.com/yongh/p/9318604.html
3.https://blog.csdn.net/w13261711130/article/details/79973502